Reputation: 3020
First of all, just to clarify...
I have done quite some searchings and readings on the existing sources (medium, stackoverflow, apple developer forum, etc.) before asking this "duplicate question" for confirming and concluding my knowledge is correct.
Before we begin, just to put the terms in very precise manner. Here's what I'm referring when I mention
Use case i'm trying to tackle
App receive push notification in BACKGROUND, QUIT & KILL states then perform certain background actions (updating Application Badge + storing the Notification in device)
content-available = 1
sent together in APNS payload. Notification banner appear, background action executed!content-available = 1
sent together in APNS payload. Notification banner appear, background action executed!ONLY if user tapped notification banner, my app gets to run those background actions (Increase badge count + storing the data).
Otherwise, if user choose to tap on App Icon to open my app. The pushed notification won't exist in my app at all, including badge count is not increase.
Background State
FORCE QUIT State
FORCE QUIT State + WiFi & Cellular data turned OFF
The tests with Whatsapp, basically concludes that it's possible to have your app awake to perform background actions (Especially with the case of FORCE QUIT State + WiFi & Cellular data turned OFF)
The only "explanation" I'm able to explain myself is, they are using PushKit notifications Framework instead of User Notification Framework.
Apparently on iOS 13, like what @hubsi has mentioned down at the comment as well as some comments from Apple forum. iOS 13 does wakes my app even the app was manually killed by the user.
Upvotes: 3
Views: 5919
Reputation: 179
This is working for us for both iOS and Android even when the app is explicitly killed by the user.
Using-
APN Request
$url = "https://api.sandbox.push.apple.com/3/device/<device_token>";
$headers = array(
"apns-push-type: voip",
"apns-expiration: 10",
"apns-topic: com.example.app.voip", // .voip as suffix to bundleID
"apns-collapse-id: lcall",
"Content-Type: application/x-www-form-urlencoded",
);
$certificate_file = config('pushnotification.apn.certificate');
$payloadArray['aps'] = [
'alert' => [
'title' => "Calling title",
'body' => "Calling body",
],
'badge' => 1,
"content-available" => 1
];
$data = json_encode($payloadArray);
$client = new Client();
$response = $client->post($url, [
'headers' => $headers,
'cert' => $certificate_file,
'curl' => [
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
],
'body'=> $data,
]);
Read official for apns-push-type
-
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns
FCM Request
$url = "https://fcm.googleapis.com/fcm/send";
$headers = array(
'Authorization' => 'key=<fcm_server_key',
'Content-Type' => 'application/json'
);
$payloadArray = [
"to" => "<device_token>",
"data" => [
"title"=> "Calling Title",
"body" => "Calling Body",
]
];
$data = json_encode($payloadArray);
$client = new Client();
$response = $client->post($url, [
'headers' => $headers,
'curl' => [
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
],
'body'=> $data,
]);
Upvotes: 0
Reputation: 69
Update swift 5.x Plus iOS 14.x
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.deplinkNotification(userInfo: response.notification.request.content.userInfo )
}
}
Update: In addition to what's mentioned below, it seems that as of iOS 13 apps get actually launched when a push notification is received in killed state.
I found that in order to have the didReceiveRemoteNotification:fetchCompletionHandler
delegate to trigger, the app needs to launch the registerForRemoteNotifications (UIApplication)
method asap when launched (e.g. in didFinishLaunchingWithOptions).
In case of React Native, opposed to what's stated below, you can actually run JS code. Though you have to wait for RN to have launched before running code, e.g. like this:
public class func didReceiveRemoteNotification(_ userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
// some RN bridged method/event
}
}
Old Answer:
There are two ways to have code run when a push notifications is received on iOS with the app being killed:
As for WhatsApp I'm pretty sure they're using PushKit (they require it anyway for incoming calls). Though I think what you described in your last test would also be possible using a Notification Service Extension:
In the extension you can process the pushed notification including its payload and write data (e.g. the chat message) to your local app storage (e.g. shared with your main app through App Groups). When the app gets opened it reads that data from storage (chat message appears without data network).
Since the question is tagged with "react-native": Please note that to my knowledge it's not possible to invoke RN bridged JavaScript code in a Notification Service Extension. You'd have to write native (Swift/Obj-C) code.
Upvotes: 2