Open muneeb-mt opened 1 year ago
What platform do you use? Android, iOS or both?
Please share your package.json
or snippet from it with libraries and they versions.
Would be helpful if you have some logs or you are able to describe what actually doesn't work as expected.
Please provide more info.
{ "name": "sensights", "version": "0.0.1", "private": true, "scripts": { "android": "react-native run-android", "cc": "rimraf node_modules/.cache/babel-loader/*,", "ios": "npm run cc && react-native run-ios", "start": "react-native start", "test": "jest", "lint": "eslint . --ext .js,.jsx,.ts,.tsx", "postinstall": "npx patch-package", "release-development": "ENVFILE=.env.development react-native run-android --variant=release" }, "dependencies": { "@react-native-community/async-storage": "^1.12.1", "@react-native-community/datetimepicker": "^6.7.0", "@react-native-community/masked-view": "^0.1.11", "@react-native-community/netinfo": "^9.3.6", "@react-native-community/push-notification-ios": "^1.10.1", "@react-native-firebase/analytics": "^16.5.0", "@react-native-firebase/app": "^16.4.4", "@react-native-firebase/crashlytics": "^16.4.4", "@react-native-firebase/messaging": "^16.4.6", "@react-native-google-signin/google-signin": "^9.0.0", "@react-native-picker/picker": "^2.4.8", "@react-navigation/bottom-tabs": "^6.4.0", "@react-navigation/native": "^6.0.13", "@react-navigation/native-stack": "^6.9.1", "@reduxjs/toolkit": "^1.9.0", "@taoqf/react-native-mqtt": "^3.0.4", "@tranzerdev/react-native-user-defaults": "github:ConnectyCube/react-native-userdefaults#main", "axios": "^0.24.0", "buffer": "^6.0.3", "hex2dec": "^1.1.2", "jetifier": "^2.0.0", "lodash": "^4.17.21", "moment": "^2.29.4", "moment-timezone": "^0.5.40", "patch-package": "^6.5.0", "postinstall-postinstall": "^2.1.0", "@taoqf/react-native-mqtt": "^3.0.4", "pushy-react-native": "^1.0.29", "react": "18.1.0", "react-native": "0.70.5", "react-native-actionsheet": "^2.4.2", "react-native-awesome-alerts": "^2.0.0", "react-native-background-fetch": "^4.1.0", "react-native-background-geolocation": "^4.0.1", "react-native-background-timer": "^2.4.1", "react-native-ble-plx": "^2.0.3", "react-native-callkeep": "github:react-native-webrtc/react-native-callkeep#master", "react-native-can-draw-overlays": "^1.0.0", "react-native-code-push": "^7.0.5", "react-native-collapsible": "^1.6.0", "react-native-config": "^1.4.11", "react-native-confirmation-code-field": "^7.3.1", "react-native-connectycube": "^3.21.0", "react-native-contacts": "^7.0.5", "react-native-device-info": "^10.3.0", "react-native-dialog": "^9.3.0", "react-native-document-picker": "^8.1.2", "react-native-dropdown-picker": "^5.4.3", "react-native-elements": "^3.4.2", "react-native-error-boundary": "^1.1.16", "react-native-event-listeners": "^1.0.7", "react-native-fast-image": "^8.6.3", "react-native-fbsdk-next": "^11.1.0", "react-native-file-viewer": "^2.1.5", "react-native-fs": "^2.20.0", "react-native-gesture-handler": "^2.8.0", "react-native-google-fit": "^0.19.1", "react-native-health": "^1.13.0", "react-native-icon-badge": "^1.1.3", "react-native-image-picker": "^4.10.1", "react-native-immediate-phone-call": "^2.0.0", "react-native-incall-manager": "^4.0.0", "react-native-invoke-app": "github:ConnectyCube/react-native-invoke-app#master", "react-native-keep-awake": "^4.0.0", "react-native-keyboard-aware-scroll-view": "^0.9.5", "react-native-linear-gradient": "^2.6.2", "react-native-loading-spinner-overlay": "^3.0.1", "react-native-maps": "^1.3.2", "react-native-material-dropdown": "^0.11.1", "react-native-modal": "^13.0.1", "react-native-modal-datetime-picker": "^14.0.0", "react-native-nodemediaclient": "^0.2.18", "react-native-notifications": "^4.3.3", "react-native-permissions": "^3.6.1", "react-native-picker-select": "^8.0.4", "react-native-push-notification": "^8.1.1", "react-native-reanimated": "^2.12.0", "react-native-restart": "^0.0.24", "react-native-safe-area-context": "^4.4.1", "react-native-safe-area-view": "^1.1.1", "react-native-screens": "^3.18.2", "react-native-share": "^8.0.0", "react-native-simple-toast": "^1.1.4", "react-native-slider": "^0.11.0", "react-native-snackbar": "^2.4.0", "react-native-sound": "^0.11.2", "react-native-splash-screen": "^3.3.0", "react-native-svg": "^13.6.0", "react-native-svg-transformer": "^1.0.0", "react-native-swiper": "^1.6.0", "react-native-vector-icons": "^9.2.0", "react-native-version-check": "^3.4.3", "react-native-veyetals-native": "^1.5.5", "react-native-webrtc": "^1.92.0", "react-native-webview": "^11.23.1", "react-native-youtube-iframe": "^2.2.2", "react-native-zendesk-chat": "^0.4.1", "react-navigation": "^4.4.4", "react-navigation-stack": "^2.10.4", "react-navigation-transitions": "^1.0.12", "react-redux": "^8.0.5", "redux-persist": "^6.0.0", "redux-saga": "^1.2.1", "rn-fetch-blob": "^0.12.0", "rn-secure-storage": "^2.0.7", "socket.io-client": "^4.5.3", "styled-content-loader": "^1.2.2", "victory-native": "^36.6.8" }, "resolutions": { "react-native-reanimated": "^2.9.1" }, "devDependencies": { "@babel/core": "^7.12.9", "@babel/runtime": "^7.12.5", "@react-native-community/eslint-config": "^2.0.0", "@tsconfig/react-native": "^2.0.2", "@types/jest": "^26.0.23", "@types/react": "^18.0.21", "@types/react-native": "^0.70.6", "@types/react-test-renderer": "^18.0.0", "@typescript-eslint/eslint-plugin": "^5.37.0", "@typescript-eslint/parser": "^5.37.0", "babel-jest": "^26.6.3", "babel-plugin-module-resolver": "^4.1.0", "eslint": "^7.32.0", "jest": "^26.6.3", "metro-react-native-babel-preset": "0.72.3", "react-test-renderer": "18.1.0", "typescript": "^4.8.3" }, "jest": { "preset": "react-native", "moduleFileExtensions": [ "ts", "tsx", "js", "jsx", "json", "node" ] } }
This is the package.json file. The point is the background call feature implementation using KeepCall is not working
Is it possible to capture logs from caller and callee sides when incoming call should present? Use real devices - Android/iOS to make a call and Android to receive the call. It will helpful to find your issues.
Otherwise I will build a project by the guide (video calling sample + notifications + callkeep) with versions of libs from your package.json
to check how it works. It will take some time. Then we look for problems on your side
Here are some logs
@ccvlad How much time you will required to create a project and verify all? And we can send call these required screenshots by tomorrow morning. I will request you to create a project using package.json to check and verify all the functionality. I can provide you the screenshots callee and caller side by tomorrow @ccvlad
I will try to check it today but I not sure that it will be tested before tomorrow.
Initially, I thought that you didn't fully configure the push-notification /VOIP. But I can't write my guesses as I need more details from you.
I need to build a project locally to make sure everything works well on our side.
Please check it at your side if it is working fine for you. In the meantime, I will double check if I have configured push notifications and VOIP properly.
@ccvlad is there any response?
I will update you today
sure - i will wait @ccvlad
Hi @muneeb-mt
I have upgraded RNVideoChat sample to React Native 0.70.5 and configured notifications with the callkeep from scratch.
The callkeep works on iOS. On Android the callkeep plays ringtone but doesn't show incoming call. I will resolve it and let you know.
What behavior did you see on your side?
@muneeb-mt
You can check pull request's diffs if it is helpful. I have upgraded the RNVideoChat the sample to React Native 0.70.5 and reviewed the CallKeep setup by our guide. CallKeep works for iOS and Android platforms.
Lets consider what can we do to setup CallKeep for you. Please check one more time the Push Notifications guide. Then describe your app's behavior for Android and iOS. I would ask you questions related to code/configs or will answer to your answers.
@ccvlad Push notification guide link is broken. It says 404: Not Found
@faisalur-rehman which one is broken?
@faisalur-rehman which one is broken?
This link is broken which @ccvlad mentioned in his above comment Push Notifications guide
I was able to open the link in incognito but it does not open in normal window for me.
I think it is an issue with my browser. I will follow the guide and will get back to you on this
@ccvlad I was going through the connectycube code for background call implementation and saw this code in AppDelegate.mm
here
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handlePushKitNotificationReceived:) name:RNPushKitNotificationReceived object:nil];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"voipIncomingCallSessions"];
But when I added this code into my code, it threw this error when building the project:
Use of undefined identifier RNPushKitNotificationReceived
I tried finding the identifier in connectycube RNVideoChat
project but couldn't find one.
Do I need to declare it somewhere or am I doing something wrong?
@faisalur-rehman make sure you also have
#import "RNNotifications.h"
#import "RNEventEmitter.h"
RNPushKitNotificationReceived
is a part of https://github.com/wix/react-native-notifications lib, which is defined in RNEventEmitter.h
file
@DaveLomber @ccvlad I completed push notification guide setup and added APNs certificate on connnectycube admin console. Made few changes in AppDelegate.mm
file.
After these changes, I am able to receive the call in background state for IOS but there are few issues.
AppDelegate.mm
code#import "AppDelegate.h"
#import "RCTAppleHealthKit.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <GoogleMaps/GoogleMaps.h>
#import <React/RCTAppSetupUtils.h>
#import <Firebase.h>
#import <UserNotifications/UserNotifications.h>
#import <RNCPushNotificationIOS.h>
#import <PushyModule.h>
#import <CodePush/CodePush.h>
#import "RNCallKeep.h"
#import "RNNotifications.h"
#import "RNEventEmitter.h"
#import "RNSplashScreen.h" // here
#import <FBSDKCoreKit/FBSDKCoreKit-swift.h>
#import <RNGoogleSignin/RNGoogleSignin.h>
#import <React/RCTLinkingManager.h>
#if RCT_NEW_ARCH_ENABLED
#import <React/CoreModulesPlugins.h>
#import <React/RCTCxxBridgeDelegate.h>
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
#import <React/RCTSurfacePresenter.h>
#import <React/RCTSurfacePresenterBridgeAdapter.h>
#import <ReactCommon/RCTTurboModuleManager.h>
#import <react/config/ReactNativeConfig.h>
static NSString *const kRNConcurrentRoot = @"concurrentRoot";
@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
RCTTurboModuleManager *_turboModuleManager;
RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
facebook::react::ContextContainer::Shared _contextContainer;
}
@end
#endif
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RCTAppSetupPrepareApp(application);
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
#if RCT_NEW_ARCH_ENABLED
_contextContainer = std::make_shared<facebook::react::ContextContainer const>();
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
_contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
_bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
#endif
NSDictionary *initProps = [self prepareInitialProps];
UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"sensights", initProps);
if (@available(iOS 13.0, *)) {
rootView.backgroundColor = [UIColor systemBackgroundColor];
} else {
rootView.backgroundColor = [UIColor whiteColor];
}
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
[FIRApp configure];
[GMSServices provideAPIKey:@"AIzaSyCM3R8cZQht5FIFqWEoEGiJNiquht_CVUU"];
[PushyModule didFinishLaunchingWithOptions:launchOptions];
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[RNSplashScreen show]; // here
[RNNotifications startMonitorNotifications];
[RNNotifications startMonitorPushKitNotifications];
[[FBSDKApplicationDelegate sharedInstance] application:application
didFinishLaunchingWithOptions:launchOptions];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handlePushKitNotificationReceived:)
name:RNPushKitNotificationReceived
object:nil];
// cleanup
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"voipIncomingCallSessions"];
return YES;
}
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);
}
- (void)handlePushKitNotificationReceived:(NSNotification *)notification {
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
if (state == UIApplicationStateBackground || state == UIApplicationStateInactive) {
// save call info to user defaults
NSMutableDictionary *callsInfo = [[[NSUserDefaults standardUserDefaults] objectForKey:@"voipIncomingCallSessions"] mutableCopy];
if (callsInfo == nil) {
callsInfo = [NSMutableDictionary dictionary];
}
[callsInfo setObject:@{
@"initiatorId": notification.userInfo[@"initiatorId"],
@"opponentsIds": notification.userInfo[@"opponentsIds"],
@"handle": notification.userInfo[@"handle"],
@"callType": notification.userInfo[@"callType"]
} forKey:notification.userInfo[@"uuid"]];
[[NSUserDefaults standardUserDefaults] setObject:callsInfo forKey:@"voipIncomingCallSessions"];
// show CallKit incoming call screen
[RNCallKeep reportNewIncomingCall: notification.userInfo[@"uuid"]
handle: notification.userInfo[@"handle"]
handleType: @"generic"
hasVideo: [notification.userInfo[@"callType"] isEqual: @"video"]
localizedCallerName: notification.userInfo[@"handle"]
supportsHolding: YES
supportsDTMF: YES
supportsGrouping: YES
supportsUngrouping: YES
fromPushKit: YES
payload: notification.userInfo
withCompletionHandler: nil];
} else {
// when an app is in foreground -> will show the in-app UI for incoming call
}
}
/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
///
/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
/// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`.
- (BOOL)concurrentRootEnabled
{
// Switch this bool to turn on and off the concurrent root
return true;
}
- (NSDictionary *)prepareInitialProps
{
NSMutableDictionary *initProps = [NSMutableDictionary new];
#ifdef RCT_NEW_ARCH_ENABLED
initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]);
#endif
return initProps;
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
return [CodePush bundleURL];
#endif
}
#if RCT_NEW_ARCH_ENABLED
#pragma mark - RCTCxxBridgeDelegate
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
{
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
delegate:self
jsInvoker:bridge.jsCallInvoker];
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
}
#pragma mark RCTTurboModuleManagerDelegate
- (Class)getModuleClassFromName:(const char *)name
{
return RCTCoreModulesClassProvider(name);
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
return nullptr;
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
initParams:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return nullptr;
}
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
return RCTAppSetupDefaultModuleFromClass(moduleClass);
}
// - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
// {
// [RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
// }
// // Required for the notification event. You must call the completion handler after handling the remote notification.
// - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
// fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
// {
// [RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
// }
// // Required for the registrationError event.
// - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
// {
// [RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
// }
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[RNNotifications didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
[RNNotifications didFailToRegisterForRemoteNotificationsWithError:error];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
[RNNotifications didReceiveBackgroundNotification:userInfo withCompletionHandler:completionHandler];
}
// Required for localNotification event
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler
{
[RNCPushNotificationIOS didReceiveNotificationResponse:response];
}
- (BOOL)application:(UIApplication )application openURL:(nonnull NSURL )url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation options:(nonnull NSDictionary<NSString ,id> )options {
return [[FBSDKApplicationDelegate sharedInstance] application:application openURL:url options:options] || [RNGoogleSignin application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url sourceApplication:sourceApplication annotation:annotation options:options];
}
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
return [RCTLinkingManager application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void(^)(NSArray * __nullable restorableObjects))restorationHandler
{
return [RNCallKeep application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[RNNotifications didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
[RNNotifications didFailToRegisterForRemoteNotificationsWithError:error];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
[RNNotifications didReceiveBackgroundNotification:userInfo withCompletionHandler:completionHandler];
}
#endif
@end
Here are some screehshots:
Thanks
@DaveLomber @ccvlad Is there any update?
@ahmaddmuneeb
To solve "Unknown" you have to pass the right parameters to the push notification's payload in ConnectyCube.pushnotifications.events.create(..)
, try to modify title/body/message inside your params:
const payload = JSON.stringify(params);
const pushParameters = {
notification_type: "push",
user: { ids: recipientsUsersIds },
environment: __DEV__ ? "development" : "production",
message: ConnectyCube.pushnotifications.base64Encode(payload),
};
ConnectyCube.pushnotifications.events.create(pushParameters)
Pay attention to the guide to keep calling in background/locked mode - https://developers.connectycube.com/reactnative/videocalling?id=continue-call-in-background
To improve a chat connection (for calls signaling) you should manage it. The way is using ReactNative's AppState listener to define the background/foreground app's state. Check the chat connection (ConnectyCube.chat.isConnected) after the app is going to the foreground and do ConnectyCube.chat.connect(params)
if it was disconnected. Also, a good way is to listen to the network state and do reconnect after your app goes from offline to online (check the lib @react-native-community/netinfo
)
Unfortunately, I don't see any of your problems in the log above. Our RNVideoChat app is a demo app and it doesn't cover all cases, but you can find more information in our guide for React Native
Please help us in the complete integration of CallKeep in our react-native application. We have already integrated the files and setup everything according to the documentation and !!RNVideoCHAT!! project. Please arrange one of your engineer to engage with us on this matter and help us to resolve all issues. Thank you. Looking forward to you.