I am developing a React Native app which uses Agora.io for making calls. Target platforms are Android and iOS. Costs and time are limited, so native (Swift + Java/Kotlin) way is not acceptable. As a trade-off, I am using react-native-callkeep to get as close to native call UI as possible.
Basically, the flow is:
- User A presses "Call" button, then he/she is taken to Call Screen, and push notification is sent to User B (callee).
- User B receives the push.
- 2.1. User B's app is in foreground. Native call UI is shown using react-native-callkeep, user presses "Answer", then he is redirected to Call Screen. This scenario works fine.
- 2.2. User B's app is in background. The push is handled by a background service (I know it may be called different on iOS/Android, but hope you get what I mean). Then, on Android I use the following code to bring app to foreground:
// In a native module:
@ReactMethod
public void launchMainActivity(String uri) {
String packageName = reactContext.getPackageName();
Intent launchIntent = reactContext.getPackageManager().getLaunchIntentForPackage(packageName);
String className = launchIntent.getComponent().getClassName();
try {
Class<?> activityClass = Class.forName(className);
Intent activityIntent;
if (uri != null) {
activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri), reactContext, activityClass);
} else {
activityIntent = new Intent(reactContext, activityClass);
}
activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
reactContext.startActivity(activityIntent);
} catch(Exception e) {
return;
}
}
MyModule.launchMainActivity(`https://myapp.com/CallScreen?parameter=${value}`); // Link is simplified
This opens the app and tells react-navigation what screen I want to open and what params I want to pass to it. This works fine on Android.
Now I want the same on iOS. I was not able to find any example of how to do the same on iOS. So I tried to use deep links, but no success. I have added this to AppDelegate.m:
#import <React/RCTLinkingManager.h>
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
return [RCTLinkingManager application:application openURL:url options:options];
}
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void(^)(NSArray * __nullable restorableObjects))restorationHandler
{
return [RNCallKeep application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
and to Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
This is how I use it:
Linking.openURL(`myapp://CallScreen?parameter=${value}`); // Link is simplified
And it says that it can not handle this link. But, if I just type the link in the browser, it suggests to open it in my app (and opens it, I get redirected to Call Screen).
So, finally, the question: how can I open my app on iOS from background service, if it is in background/killed? A way similar to how it is done on Android is highly preferred over linking.
BTW, this is how background service is registered (firebase is used):
import messaging from '@react-native-firebase/messaging';
messaging().setBackgroundMessageHandler(async message => {
// Here we go
});
P.S.:
- Background messaging itself works fine on iOS/Android.
- react-native-callkeep works on iOS/Android.
- Call flow works fine when app is in foreground on iOS/Android.
- I have configured react-navigation for linking (and linking itself works on both iOS/Android).