i've the following situation.
2 identical react-native apps (differs only for bundleId, app icon etc) structured like this:
-> project structure
My goal it's to emit an event from native side to the JS layer through the bridge when a push notification has been received or tapped by the user (assuming that the app is in foreground and app has finished launching).
On the first App the following code works as expected when i trigger a push notification to my simulator with the command xcrun simctl push <device-id> <bundleId> <filename>.apns, the second app crash immediatly with the following error:
Thread 1: "Error when sending event: pushDelivered with body: <the string passed as body>. RCTCallableJSModules is not set. This is probably because you've explicitly synthesized the RCTCallableJSModules in CustomEventsEmitter, even though it's inherited from RCTEventEmitter."
-> xcode view
Here is the code implementation of RCTEventEmitter's sendEventWithName that provoke the assertion.
I don't know if it's a problem with my implementation. In 1 of the 2 apps works like a charm, in the other 💥.
Anyone can help me find the problem in the code ? Probably a problem with the bridge?
i've tried many times to reinstall pods, clean project and rebuild. The code works on the project A and not on the project B.. i cannot figure out the reason
AppDelegate.h
#import <React/RCTBridgeDelegate.h>
#import <React/RCTBridgeModule.h>
#import <UIKit/UIKit.h>
#import <UserNotifications/UserNotifications.h>
#import <UserNotifications/UNUserNotificationCenter.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate, RCTBridgeModule, UNUserNotificationCenterDelegate>
#property (nonatomic, strong) UIWindow *window;
#property (nonatomic, strong) NSDictionary *receivedNotificationUserInfo;
#end
AppDelegate.mm
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <React/RCTAppSetupUtils.h>
#import <UserNotifications/UserNotifications.h>
#import "CustomEventsEmitter.h"
#implementation AppDelegate
bool hasFinishedLaunching = false;
CustomEventsEmitter *customEventsEmitter = NULL;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
hasFinishedLaunching = true;
customEventsEmitter = [CustomEventsEmitter allocWithZone: nil];
RCTAppSetupPrepareApp(application);
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
NSDictionary *initProps = [self prepareInitialProps];
UIView *rootView = RCTAppSetupDefaultRootView(bridge, #"MyAppName", 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];
// Define UNUserNotificationCenter
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
return YES;
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:#"index"];
#else
return [[NSBundle mainBundle] URLForResource:#"main" withExtension:#"jsbundle"];
#endif
}
-(void)applicationDidBecomeActive:(UIApplication *)application
{
application.applicationIconBadgeNumber = 0;
}
// The method will be called on the delegate when the user responded to the notification by opening
// the application, dismissing the notification or choosing a UNNotificationAction. The delegate
// must be set before the application returns from applicationDidFinishLaunching:.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler {
NSLog(#"didReceiveNotificationResponse response: %#", response);
NSDictionary *userInfo = response.notification.request.content.userInfo;
if (userInfo[#"_od"]){
// if no listeners has been registered yet, store the value
// this is the case when the notification was clicked from closed app
if(![customEventsEmitter hasListeners]) {
// handle this case ...
}
// if listeners has been registered, emit an event
// this is the case when the notification was clicked from foreground app
else {
[self emitPushTappedEvent:userInfo[#"_od"]];
}
}
if (completionHandler != nil) {
completionHandler();
}
}
//Called when a notification is delivered to a foreground app.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
NSDictionary *userInfo = notification.request.content.userInfo;
NSLog(#"User Info : %#", userInfo);
[self emitPushDeliveredEvent:userInfo[#"_od"]];
completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);
}
-(void)emitPushDeliveredEvent:(NSString*)value {
NSLog(#"emitPushDeliveredEvent called");
[customEventsEmitter sendEventWithName:#"pushDelivered" body:value];
}
-(void)emitPushTappedEvent:(NSString*)value {
NSLog(#"emitPushTappedEvent called");
[customEventsEmitter sendEventWithName:#"pushTapped" body:value];
}
#end
And this are the CustomEventsEmitter files:
CustomEventsEmitter.h
#ifndef CustomEventsEmitter_h
#define CustomEventsEmitter_h
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#interface CustomEventsEmitter : RCTEventEmitter <RCTBridgeModule>
- (void)sendEventName:(NSString *)eventName body:(id)body;
- (bool)hasListeners;
#end
#endif
CustomEventsEmitter.m
#import "CustomEventsEmitter.h"
#implementation CustomEventsEmitter
{
bool hasListeners;
}
RCT_EXPORT_MODULE(CustomEventsEmitter);
+ (id)allocWithZone:(NSZone *)zone {
static CustomEventsEmitter *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [super allocWithZone:zone];
});
return sharedInstance;
}
- (NSArray<NSString *> *)supportedEvents {
return #[#"pushDelivered", #"pushTapped"];
}
// Will be called when this module's first listener is added.
-(void)startObserving {
hasListeners = YES;
// Set up any upstream listeners or background tasks as necessary
}
// Will be called when this module's last listener is removed, or on dealloc.
-(void)stopObserving {
hasListeners = NO;
// Remove upstream listeners, stop unnecessary background tasks
}
-(bool)hasListeners {
return hasListeners;
}
- (void)sendEventName:(NSString *)eventName body:(id)body {
if (hasListeners) {
NSLog(#"CustomEventsEmitter sendEventName emitting event: %#", eventName);
[self sendEventWithName:eventName body:body];
} else {
NSLog(#"CustomEventsEmitter sendEventName called without listeners: %#", eventName);
}
}
#end
HELP ME UNDERSTAND PLEASEEEE
Oh i've solved it!
It was a mistake of mine.
The AppModule didn't invoke the CustomEventsEmitter's methods correctly..
changing the code like below makes the events be emitted correctly through the RN bridge
-(void)emitPushDeliveredEvent:(NSString*)value {
NSLog(#"emitPushDeliveredEvent called");
[customEventsEmitter sendEventName:#"pushDelivered" body:value];
//[customEventsEmitter sendEventWithName:#"pushDelivered" body:value];
}
-(void)emitPushTappedEvent:(NSString*)value {
NSLog(#"emitPushTappedEvent called");
[customEventsEmitter sendEventName:#"pushTapped" body:value];
//[customEventsEmitter sendEventWithName:#"pushTapped" body:value];
}
Related
I'm implementing Lottie SplashScreen, and I have to do some stuff on Xcode, I copied the code from the Lottie guide, but it is giving me semantic issues, but I have no clue on how to fix it, here is the code
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import "RNBootSplash.h"
#import <React/RCTRootView.h>
#import <UserNotifications/UserNotifications.h>
#import <RNCPushNotificationIOS.h>
#import "RNSplashScreen.h"
#import "EmpathoApp-Swift.h"
#ifdef FB_SONARKIT_ENABLED
#import <FlipperKit/FlipperClient.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
static void InitializeFlipper(UIApplication *application) {
FlipperClient *client = [FlipperClient sharedClient];
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
[client addPlugin:[FlipperKitReactPlugin new]];
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
[client start];
}
#endif
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
#ifdef FB_SONARKIT_ENABLED
InitializeFlipper(application);
#endif
// Define UNUserNotificationCenter
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:#"EmpathoApp"
initialProperties:nil];
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];
[RNBootSplash initWithStoryboard:#"BootSplash" rootView:rootView];
//Lottie Implementation
Dynamic *t = [Dynamic new];
UIView *animationView = [t createAnimationViewWithRootView:rootView lottieName:#"splashscreen"];
animationView.backgroundColor = [UIColor blueColor]; // change backgroundColor
// register LottieSplashScreen to RNSplashScreen
[RNSplashScreen showLottieSplash:animationView inRootView:rootView];
// play
[t playWithAnimationView:animationView];
// If you want the animation layout to be forced to remove when hide is called, use this code
[RNSplashScreen setAnimationFinished:true];
return YES;
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:#"index" fallbackResource:nil];
#else
return [[NSBundle mainBundle] URLForResource:#"main" withExtension:#"jsbundle"];
#endif
}
// Required for the register event.
- (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];
}
// Required for localNotification event
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler
{
[RNCPushNotificationIOS didReceiveNotificationResponse:response];
}
//Called when a notification is delivered to a foreground app.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);
}
#end
I'm having a problem with Dynamic*t I get this error "Use of undeclared identifier 'Dynamic'" and "Use of undeclared identifier 't'" how can I declare them correctly?
Thanks
I've been trying to setup notifications on an IOS app for several days and I'm facing many issues.
One that i cannot figure out how it happens is the following :
In appDelegate.m :
Error
I do not understand the error given the fact that I'm a React-native developper but it seems really strange.
Here is my full AppDelegate.m File :
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <React/RCTLinkingManager.h>
#import <UserNotifications/UserNotifications.h>
#import <RNCPushNotificationIOS.h>
#ifdef FB_SONARKIT_ENABLED
#import <FlipperKit/FlipperClient.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
#import <GoogleMaps/GoogleMaps.h>
static void InitializeFlipper(UIApplication *application) {
FlipperClient *client = [FlipperClient sharedClient];
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
[client addPlugin:[FlipperKitReactPlugin new]];
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
[client start];
}
#endif
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
if ([url.path isEqualToString:#"/"]) {
NSString *fixedString = [NSString stringWithFormat:#"%#://?%#", url.scheme, url.query]; //Pour solve l'issue suivante : https://github.com/aws-amplify/amplify-js/issues/7468
NSURL *fixedURL = [NSURL URLWithString:fixedString];
return [RCTLinkingManager application:application openURL:fixedURL options:options];
}
return [RCTLinkingManager application:application openURL:url options:options];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[GMSServices provideAPIKey:#"xxxxxx"]; // add this line using the api key obtained from Google Console
#ifdef FB_SONARKIT_ENABLED
InitializeFlipper(application);
#endif
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:#"Villeo"
initialProperties:nil];
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];
// Define UNUserNotificationCenter
UNUserNotificationCenter *center =
[UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
return YES;
}
// Called when a notification is delivered to a foreground app.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:
(void (^)(UNNotificationPresentationOptions options))
completionHandler {
completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionBadge |
UNNotificationPresentationOptionAlert);
}
// Required for the register event.
- (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)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler {
[RNCPushNotificationIOS didReceiveNotificationResponse:response];
completionHandler();
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:#"index" fallbackResource:nil];
#else
return [[NSBundle mainBundle] URLForResource:#"main" withExtension:#"jsbundle"];
#endif
}
#end
I've followed the best I could the setup instructions from : https://github.com/react-native-push-notification/ios#augment-appdelegate
Thanks in advance 🤝
I'm working on a brownfield integration on react-native-asyncstorage.
In the pod file, RNCAsyncStorage.h has the following:
#import <React/RCTBridgeModule.h>
#import <React/RCTInvalidating.h>
#import "RNCAsyncStorageDelegate.h"
...
#interface RNCAsyncStorage : NSObject <RCTBridgeModule,RCTInvalidating>
...
- (void)multiGet:(NSArray<NSString *> *)keys callback:(RCTResponseSenderBlock)callback;
And in my AppDelegate.m I have
#implementation AppDelegate {
__weak RCTBridge *_bridge;
}
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
...
}
And in my Stuff.m I have this in my method:
#import <RNCAsyncStorage/RNCAsyncStorage.h>
....
RNCAsyncStorage *asyncStorage = [self.bridge moduleForClass:[RNCAsyncStorage class]];
[asyncStorage multiGet:#[#"playerQueue"]] callback:^(NSArray *response){
NSObject *count = response[0];
if ([count isKindOfClass:[NSError class]]) {
// Failed to get count
return;
}
// Use count here
}];
But I kept getting the error saying No visible #interface for 'RNCAsyncStorage' declares the selector 'multiGet:'.
There's a multiGet selector being declared in the header file as well as in the .m file.
I should say that RNCAsyncStorage is imported from Pods, but I did try to pull those into my project and still getting the same error. Anything I should do to address this? Thanks!
Just a mistake in syntax. There is an extra ], the correct call is:
[asyncStorage multiGet:#[#"playerQueue"] callback:^(NSArray *response){
NSObject *count = response[0];
if ([count isKindOfClass:[NSError class]]) {
// Failed to get count
return;
}
// Use count here
}];
My app developed in Xcode with Objective-C should ask for the camera permission in order to reply to a SIP video call.
Although i wrote the Privacy - Camera Usage Description Key into my info.plist file the app only asks for the microphone permission and not for the camera permission and when I start a video call it crash.
This is my info.plist file:
My info.plist file
Also, If I go to app settings in iOS Settings there is no camera permission switch.
Update with code as requested
To make a video call i use the ABTO VoIP SDK.
AppDelegate.h
#import <UIKit/UIKit.h>
#import <AbtoSipClientWrapper/AbtoSipPhoneObserver.h>
#import "Global.h"
#include "GenDefs.h"
#define kNotifKey #"key"
#define kNotifKey_IncomingCall #"icall"
#define kNotifKey_IncomingMsg #"imsg"
#define kNotifCall_SessionId #"sid"
#define kNotifCall_RemoteInfo #"rinfo"
#define kNotifKey_IncomingIm #"iim"
#interface ImMessage : NSObject {
#public
NSString *from;
NSString *to;
NSString *text;
BOOL isRead;
}
#end
#interface AppDelegate : UIResponder <UIApplicationDelegate, AbtoPhoneInterfaceObserver> {
#public
UINavigationController *navController;
UILocalNotification *lastCallNotification;
BOOL checkIconLaunch;
NSMutableArray *imMessages;
}
+ (AppDelegate *)sharedInstance;
#property (readwrite,nonatomic) AbtoPhoneInterface* phone;
#property (retain, nonatomic) UIWindow *window;
#property (retain, nonatomic) UINavigationController *navController;
#property (strong, nonatomic) UILocalNotification *lastCallNotification;
#property (nonatomic) BOOL checkIconLaunch;
#property (nonatomic) BOOL connected;
- (void)addMessage:(ImMessage *)message;
- (NSMutableArray *)getIMs;
- (void)restoreIms;
- (void)storeIms;
#end
AppDelegate.m
#import "AppDelegate.h"
#interface AppDelegate () {
}
#end
#implementation AppDelegate
#synthesize phone;
+ (AppDelegate *)sharedInstance{
return (AppDelegate *)[UIApplication sharedApplication].delegate;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
phone = [AbtoPhoneInterface new];
[phone initialize:self];
return YES;
}
#pragma mark - UISceneSession lifecycle
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return [[UISceneConfiguration alloc] initWithName:#"Default Configuration" sessionRole:connectingSceneSession.role];
}
- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
- (void)applicationWillTerminate:(UIApplication *)application {
[phone deinitialize];
}
#pragma mark Abto SIP SDK delegate
- (void)onRegistered:(NSInteger)accId {
//[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_PHONE_EVENT object:#(PhoneEventsRegSuccess)];
}
- (void)onRegistrationFailed:(NSInteger)accId statusCode:(int)statusCode statusText:(NSString*)statusText {
// [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_PHONE_EVENT object:#(PhoneEventsRegFailed)];
}
- (void)onUnRegistered:(NSInteger)accId {
// [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_PHONE_EVENT object:#(PhoneEventsUnregSuccess)];
}
- (void)onRemoteAlerting:(NSInteger)accId statusCode:(int)statusCode {
// [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_PHONE_EVENT object:#(PhoneEventsRemoteAlerting)];
}
- (void)onIncomingCall:(NSInteger)callId remoteContact:(NSString *)remoteContact {
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_CALL_EVENT object:#(CallEventsIncoming) userInfo:#{CALL_ID_ARGUMENT:#(callId), CONTACT_ARGUMENT:remoteContact}];
}
- (void)onCallConnected:(NSInteger)callId remoteContact:(NSString *)remoteContact {
// [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_CALL_EVENT object:#(CallEventsConnected) userInfo:#{CALL_ID_ARGUMENT:#(callId)}];
}
- (void)onCallDisconnected:(NSInteger)callId remoteContact:(NSString *)remoteContact statusCode:(NSInteger)statusCode message:(NSString *)message {
// [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_CALL_EVENT object:#(CallEventsDisconnected) userInfo:#{CALL_ID_ARGUMENT:#(callId), STATUS_ARGUMENT:#(statusCode)}];
}
- (void)onCallAlerting:(NSInteger)callId statusCode:(int)statusCode {
// [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_CALL_EVENT object:#(CallEventsAlerting) userInfo:#{CALL_ID_ARGUMENT:#(callId), STATUS_ARGUMENT:#(statusCode)}];
}
- (void)onPresenceChanged:(NSString *)uri status:(PhoneBuddyStatus)status note:(NSString *)note {
}
- (void)onCallHeld:(NSInteger)callId state:(BOOL)state {
}
- (void)onToneReceived:(NSInteger)callId tone:(NSInteger)tone {
}
- (void)onTextMessageReceived:(NSString *)from to:(NSString *)to body:(NSString *)body {
}
- (void)onTextMessageStatus:(NSString *)address reason:(NSString *)reason status:(BOOL)status {
}
- (void)onTransferStatus:(NSInteger)callId statusCode:(int)statusCode message:(NSString *)message {
// [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_CALL_EVENT object:#(CallEventsTransfering) userInfo:#{CALL_ID_ARGUMENT:#(callId), STATUS_ARGUMENT:#(statusCode), MESSAGE_ARGUMENT:message}];
}
- (void)onZrtpSas:(NSInteger)callId sas:(NSString *)sas {
// [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_CALL_EVENT object:#(CallEventsZrtpSas) userInfo:#{CALL_ID_ARGUMENT:#(callId), MESSAGE_ARGUMENT:sas}];
}
- (void)onZrtpSecureState:(NSInteger)callId secured:(BOOL)secured {
NSLog(#"ZRTP secured = %#", secured ? #"YES" : #"NO");
// [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_CALL_EVENT object:#(CallEventsZrtpSecureState) userInfo:#{CALL_ID_ARGUMENT:#(callId), STATUS_ARGUMENT:#(secured)}];
}
- (void)onZrtpError:(NSInteger)callId error:(NSInteger)error subcode:(NSInteger)subcode {
NSLog(#"ZRTP error = %ld(subcode = %ld)", (long)error, (long)subcode);
// [[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_CALL_EVENT object:#(CallEventsZrtpSecureState) userInfo:#{CALL_ID_ARGUMENT:#(callId), STATUS_ARGUMENT:#(error)}];
}
#end
VideoCallViewController.h
This is the "scene" presented when a SIP call is coming.
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
NS_ASSUME_NONNULL_BEGIN
#interface VideoCallViewController : UIViewController {
BOOL isRecording;
BOOL enableSpeaker;
BOOL isFrontCamera;
BOOL isVideoMute;
BOOL sendingVideo;
}
#property (weak, nonatomic) IBOutlet UIImageView *imageViewRemoteVideo;
#property (weak, nonatomic) IBOutlet UIButton *buttonPick;
#property (weak, nonatomic) IBOutlet UIButton *buttonHangUp;
#property (weak, nonatomic) IBOutlet UIButton *buttonHangUpLadge;
#property(nonatomic, retain) NSString *number;
#property(nonatomic, assign) NSInteger callId;
#property(nonatomic, assign) BOOL incoming;
- (IBAction)onButtonClick:(UIButton *)sender;
#end
NS_ASSUME_NONNULL_END
VideoCallViewController.m
#import "VideoCallViewController.h"
#import <AVFoundation/AVCaptureOutput.h>
#import <AVFoundation/AVCaptureDevice.h>
#import <AVFoundation/AVCaptureInput.h>
#import <AVFoundation/AVMediaFormat.h>
#import <QuartzCore/QuartzCore.h>
#define ACTION_SPEAKER_ON #"Turn Speaker On"
#define ACTION_SPEAKER_OFF #"Turn Speaker Off"
#define ACTION_OPEN_DTMF #"Send DTMF"
#define ACTION_START_RECORDING #"Start Recording"
#define ACTION_STOP_RECORDING #"Stop Recording"
#define ACTION_SHOW_RTT #"Show RTT"
#define kColorsDarkBlack [NSArray arrayWithObjects: \
(id)[[UIColor colorWithRed:.1f green:.1f blue:.1f alpha:0.7] CGColor], \
(id)[[UIColor colorWithRed:0.f green:0.f blue:0.f alpha:0.7] CGColor], \
nil]
#define kColorsBlue [NSArray arrayWithObjects: \
(id)[[UIColor colorWithRed:.0f green:.0f blue:.5f alpha:0.7] CGColor], \
(id)[[UIColor colorWithRed:0.f green:0.f blue:1.f alpha:0.7] CGColor], \
nil]
#define kColorsLightBlack [NSArray arrayWithObjects: \
(id)[[UIColor colorWithRed:.2f green:.2f blue:.2f alpha:0.7] CGColor], \
(id)[[UIColor colorWithRed:.1f green:.1f blue:.1f alpha:0.7] CGColor], \
(id)[[UIColor colorWithRed:0.f green:0.f blue:0.f alpha:0.7] CGColor], \
nil]
#interface VideoCallViewController ()
#end
#implementation VideoCallViewController {
NSInteger dtmfLen;
}
#synthesize imageViewRemoteVideo;
#synthesize buttonPick;
#synthesize buttonHangUp;
#synthesize buttonHangUpLadge;
- (id)init {
self = [super init];
if (self) {
isRecording = NO;
enableSpeaker = YES;
dtmfLen = 0;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(onPhoneNotification:) name:NOTIFICATION_PHONE_EVENT object:nil];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(onCallNotification:) name:NOTIFICATION_CALL_EVENT object:nil];
[UIDevice currentDevice].proximityMonitoringEnabled = YES;
AbtoPhoneInterface* phone = [AppDelegate sharedInstance].phone;
[phone setRemoteView:self.imageViewRemoteVideo];
// [phone setLocalView:viewLocalVideo];
if (self.incoming) {
// labelStatus.text = #"Incoming video call from";//NSLocalizedString(#"INVIDEOCALL_KEY", #"");
buttonHangUp.hidden = NO;
buttonPick.hidden = NO;
buttonHangUpLadge.hidden = YES;
} else {
self.callId = [phone startCall:self.number withVideo:YES];
// labelStatus.text = #"Dialing";//NSLocalizedString(#"VIDEOCALL_KEY", #"");
// buttonPick.hidden = YES;
// buttonHangUp.hidden = YES;
buttonHangUpLadge.hidden = NO;
}
/* labelRemoteParty.text = self.number;
labelRemoteParty.hidden = NO;
buttonActions.hidden = YES;
stopVideoButton.hidden = YES;
switchCameraButton.hidden = YES; */
// imageViewRemoteVideo.hidden = YES;
// viewLocalVideo.hidden = YES;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (self.callId == kInvalidCallId) {
[self closeView];
}
}
- (void)onCallNotification:(NSNotification *)notification {
}
- (void)onPhoneNotification:(NSNotification *)notification {
}
- (void)closeView {
/* if (self == [ApplicationDelegate.navController topViewController])
[ApplicationDelegate.navController popViewControllerAnimated:YES];
DLog(#"closeView"); */
}
- (IBAction)onButtonClick:(UIButton *)sender {
AbtoPhoneInterface* phone = [AppDelegate sharedInstance].phone;
if(sender == buttonHangUp || sender== buttonHangUpLadge) {
[phone hangUpCall:self.callId status:486]; /* TODO: 0 - use defalt status */
} else if(sender == buttonPick) {
[phone answerCall:self.callId status:200 withVideo:YES];
}
}
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController {
NSString* vcNumber;
NSInteger vcCallId;
BOOL vcIncoming;
}
- (void)viewDidLoad {
[super viewDidLoad];
AbtoPhoneConfig* config = [AppDelegate sharedInstance].phone.config;
// [config loadFromUserDefaults:SETTINGS_KEY];
config.regUser = #"myUsernameHere";
config.regPassword = #"myPassHere";
config.regDomain = #"sip.antisip.com";
[AppDelegate.sharedInstance.phone finalizeConfiguration];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(onCallNotification:) name:NOTIFICATION_CALL_EVENT object:nil];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(onCallNotification:) name:NOTIFICATION_CALL_EVENT object:nil];
}
- (void)onCallNotification:(NSNotification *)notification {
NSLog(#"Inizializzare CAll view");
NSInteger status = [[notification object] integerValue];
if (status == CallEventsIncoming) {
NSInteger callId = [[notification.userInfo valueForKey:CALL_ID_ARGUMENT] integerValue];
NSString *contact = [notification.userInfo valueForKey:CONTACT_ARGUMENT];
if (callId != kInvalidCallId) {
UIApplication *app = [UIApplication sharedApplication];
AppDelegate *appDelegate = [AppDelegate sharedInstance];
NSString *remotePartyNumber = [AbtoPhoneInterface sipUriUsername:contact];
UIApplicationState state = app.applicationState;
[appDelegate.phone setSpeakerphoneOn:YES];
if ((state == UIApplicationStateBackground) || (state == UIApplicationStateInactive)) {
UILocalNotification *localNotification = [UILocalNotification new];
if (localNotification) {
localNotification.alertBody = [NSString stringWithFormat:#"%# %#", remotePartyNumber, #"calling"];
// localNotif.soundName = UILocalNotificationDefaultSoundName;
localNotification.applicationIconBadgeNumber = ++app.applicationIconBadgeNumber;
localNotification.repeatInterval = 0;
NSDictionary *userInfo = #{ kNotifKey: kNotifKey_IncomingCall,
kNotifCall_SessionId : #(callId),
kNotifCall_RemoteInfo: contact };
localNotification.userInfo = userInfo;
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
// ApplicationDelegate.lastCallNotification = localNotification;
}
} else {
vcNumber = remotePartyNumber;
vcCallId = callId;
vcIncoming = YES;
[self performSegueWithIdentifier:#"segue1" sender:self];
/* VideoCallViewController *nextController = [appDelegate.phone isVideoCall:callId] ? [VideoCallViewController new] : [VideoCallViewController new];
nextController.number = remotePartyNumber;
nextController.callId = callId;
nextController.incoming = YES;
[appDelegate.navController pushViewController:nextController animated:YES]; */
}
}
} else if (status == CallEventsDisconnected) {
// ApplicationDelegate.lastCallNotification = nil;
}
}
- (void)onPhoneNotification:(NSNotification *)notification {
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:#"segue1"]) {
VideoCallViewController *nextController = [segue destinationViewController];
nextController.number = vcNumber;
nextController.callId = vcCallId;
nextController.incoming = vcIncoming;
}
}
#end
The call code is fine, because I tested it multiple times. The issue is that the app does not ask for the camera permission.
I've just update Xcode to version 8.3.3 and pushRegistry:didUpdatePushCredentials:forType: is not being called anymore.
Did something related to PushKit changed in this new version of Xcode?
This is my code for registering:
_voipRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
_voipRegistry.delegate = self;
_voipRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
There is no change to Xcode version 8.3.3 with pushkit. There is syntax level change with swift language from 2.2 to 3.X, but nothing changed with Objective C. ( I see your code is in Objective C )
I suggest once you can cross verify your code.
AppDelegate.h
#import <UIKit/UIKit.h>
#import <PushKit/PushKit.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate,PKPushRegistryDelegate>
{
PKPushRegistry *pushRegistry;
}
#property (strong, nonatomic) UIWindow *window;
#end
AppDelegate.m
#import "AppDelegate.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
pushRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
pushRegistry.delegate = self;
pushRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
return YES;
}
#define PushKit Delegate Methods
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type{
if([credentials.token length] == 0) {
NSLog(#"voip token NULL");
return;
}
NSLog(#"PushCredentials: %#", credentials.token);
}
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type
{
NSLog(#"didReceiveIncomingPushWithPayload");
}
Refer
Hope this helps you.