Quickblox webrtc video call receive method is not called - ios

Quickblox webrtc video call receive method is not called .I am call to someone he accept the call and we can communicate but while he is calling me i am not geting that call.
`
- (void)didReceiveNewSession:(QBRTCSession *)session userInfo:(NSDictionary *)userInfo {
if (self.session ) {
[session rejectCall:#{#"reject" : #"busy"}];
return;
}
self.session = session;
[QBRTCSoundRouter.instance initialize];
NSParameterAssert(!self.nav);
IncomingCallViewController *incomingViewController =
[self.storyboard instantiateViewControllerWithIdentifier:#"IncomingCallViewController"];
incomingViewController.delegate = self;
incomingViewController.session = session;
incomingViewController.usersDatasource = self.dataSource;
self.nav = [[UINavigationController alloc] initWithRootViewController:incomingViewController];
[self presentViewController:self.nav animated:NO completion:nil];
}

The Quickblox webrtc video call receive method only called when the user is online so make sure you add in Your -
(Void)ViewDidLoad{
[QBRequest logInWithUserLogin:#"xxxxxx"
password:#"xxxxx"
successBlock:^(QBResponse * _Nonnull response, QBUUser * _Nullable user)
{
}];
[[QBChat instance] connectWithUser:self.user completion:^(NSError * _Nullable error) {
NSLog(#"User%#",self.user);
}];
}
It will be called.

Related

CXProviderDelegate methods are not triggered

I am trying to integrate CallKit into my Voip app. I referred to the SpeakerBox sample code from Apple WWDC. I created a ProviderDelegate class and I am able to see the incoming call UI after calling reportNewIncomingCall method.
But when I tap on the "Answer"/"End" button, the respective provider delegates are not fired. What could be wrong here?
Please note that "providerDidBegin" is called when I instantiate the CallProviderDelegate.
#implementation CallProviderDelegate
- (instancetype)init
{
self = [super init];
if (self) {
_providerConfiguration = [self getProviderConfiguration];
_provider = [[CXProvider alloc] initWithConfiguration:_providerConfiguration];
[_provider setDelegate:self queue:nil];
}
return self;
}
- (void)providerDidBegin:(CXProvider *)provider {
// this is getting called
}
- (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action {
// this is not getting called when the Answer button is pressed
}
- (void)reportNewIncomingCallWithUUID:(nonnull NSUUID *)UUID handle:(nonnull NSString *)handle
completion:(nullable void (^)(NSError *_Nullable error))completion {
CXCallUpdate *update = [[CXCallUpdate alloc] init];
update.remoteHandle = [[CXHandle alloc] initWithType:CXHandleTypePhoneNumber value:handle];
update.hasVideo = NO;
[_provider reportNewIncomingCallWithUUID:UUID update:update completion:^(NSError * _Nullable error) {
completion(error);
}];
}
In Caller Class:
CallProviderDelegate *providerDelegate = [[CallProviderDelegate alloc] init];
[providerDelegate reportNewIncomingCallWithUUID:[NSUUID UUID] handle:#"Raj" completion:^(NSError * _Nullable error) {
//
}];
In your "caller" class, i.e. the code in which you instantiate the CallProviderDelegate class and assign it to the providerDelegate variable, are you storing the providerDelegate object reference in an instance variable or property? If it is only being assigned to a temporary local variable, then the CallProviderDelegate object will be deallocated after the calling method finishes executing, and if the CallProviderDelegate object is deallocated then no further CXProvider delegate messages will be delivered.
I'd check that your CallProviderDelegate object is not being accidentally deallocated first.

WatchKit App Connectivity Issues

I'm trying to make a simple watch app that displays information sent by the companion app. I'm having some trouble getting the WatchKit app to properly receive the information.
On the sender side I have the following code:
- (void)viewDidLoad {
[super viewDidLoad];
// Prevents UIWebView from displaying under nav bar
self.navigationController.navigationBar.translucent = NO;
_timer = [NSTimer scheduledTimerWithTimeInterval:12.0 target:self selector:#selector(showAlert) userInfo:nil repeats:NO];
_diningLocations = [[NSMutableArray alloc] initWithCapacity:0];
if ([WCSession isSupported]) {
self.session = [WCSession defaultSession];
self.session.delegate = self;
[self.session activateSession];
// The following line works
//[self.session updateApplicationContext:#{#"hello" : #"world"} error:nil];
}
- (void)grabLocationsFromServer {
_query = [PFQuery queryWithClassName:self.tableName];
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
[_query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// Do stuff
[self.locationTable reloadData];
[self loadWatchApp];
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
[MBProgressHUD hideHUDForView:self.view animated:YES];
}
[MBProgressHUD hideHUDForView:self.view animated:YES];
}];
}
- (void)loadWatchApp {
if(self.session) {
if (self.session.paired && self.session.watchAppInstalled) {
NSError *error;
[self.session updateApplicationContext:#{#"Locations": self.diningLocations} error:&error];
}
}
}
On the receiving end I have this simple code snippet:
func loadTableData(data: [RFDiningLocation]) {
table.setNumberOfRows(data.count, withRowType: "location")
for i in 0..<data.count {
let row = table.rowControllerAtIndex(i) as! RFDiningRowController
// row.label.setText(data[i].name)
row.label.setText("Hello, world!")
}
}
When I call updateApplicationContext in viewDidLoad, it works 100% fine, but when I call it from within another function the WatchKit app just doesn't respond. I can confirm that loadWatchApp is called as well as updateApplicationContext. Thanks!
I would implement the session function from WCSessionDelegate activationDidCompleteWithState and then in the callback if state is activated then call your grabLocationsFromServer function. If grabLocationsFromServer gets called before you activate the Watch session, that could be why your application context isn't being updated.
Also, it's suggested that you call activate session as soon as possible, such as in the init of the App Delegate.
I was just experimenting before you said this worked for you, so here's what I'm seeing:
On startup of watch (initial connection), there is a call to activationDidCompleteWithState but there is no context yet, so didReceiveApplicationContext is not called.
Watch app updates per expected applicationContext only occurs when I send an empty message in sessionReachabilityDidChange. My understanding is that I have to "awake" the phone app in the background by sending this initial message. This message can be ignored on the phone side.
func sessionReachabilityDidChange(session: WCSession) {
if session.reachable {
sendMessage(["InitialMessage": true], replyHandler: nil, errorHandler: nil)
}
}

Receive Watch OS message on iOS device

Hi everyone and thanks for your support in advance,
I just started working with Watch OS 2 and Objective-C and I am trying to send a message to an iPhone device when a button is tapped, I don't know if the next approach is the best but from Apple docs it seems to best feet my needs, as I need to send a request to and paired iOS device and receive some user info, I also read that this only works if the app in in foreground witch is a downside :(
Update 1
- (IBAction)didTappedButton {
WCSession *session = [WCSession defaultSession];
session.delegate = self;
[session activateSession];
if ([session isReachable] == YES) {
NSDictionary *postDictionarry = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObject:#"retrieveAPISessionKey"] forKeys:[NSArray arrayWithObject:#"request"]];
[self.button setBackgroundColor:[UIColor blueColor]];
[session sendMessage:postDictionarry
replyHandler:^(NSDictionary<NSString *,id> * _Nonnull replyMessage) {
[self postToServer];
}
errorHandler:^(NSError * _Nonnull error) {
[self.button setBackgroundColor:[UIColor redColor]];
[self showAlertViewwithTitle:#"Oops..." andMessage:#"Something went Wrong"];
}];
}else{
[self showAlertViewwithTitle:#"Oops..." andMessage:#"Please pair with a device"];
}
}
And in the AppDelegate of I implemeted the next code in .h:
#import WatchConnectivity;
#interface AppDelegate : UIResponder <UIApplicationDelegate, UIGestureRecognizerDelegate, WCSessionDelegate>
and in the .m:
- (void)session:(nonnull WCSession *)session
didReceiveMessage:(NSDictionary<NSString *,id> *)message
replyHandler:(void(^)(NSDictionary<NSString *,id> *))replyHandler {
NSString *action = message[#"request"];
NSString *actionPerformed;
// more code here...
}
note I am testing on the simulator and have an issues in getting tap gestures and also I see a lot of spinners on the watch simulator
Update 2
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
// Configure interface objects here.
WCSession *session = [WCSession defaultSession];
session.delegate = self;
[session activateSession];
}
- (IBAction)didTappedButton {
if ([[WCSession defaultSession] isReachable] == YES) {
NSDictionary *postDictionarry = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObject:#"retrieveAPISessionKey"] forKeys:[NSArray arrayWithObject:#"request"]];
[self.button setBackgroundColor:[UIColor blueColor]];
[[WCSession defaultSession] sendMessage:postDictionarry
replyHandler:^(NSDictionary<NSString *,id> * _Nonnull replyMessage) {
[self postData];
}
errorHandler:^(NSError * _Nonnull error) {
[self.button setBackgroundColor:[UIColor redColor]];
[self showAlertViewwithTitle:#"Oops..." andMessage:#"Something went Wrong"];
}];
}else{
[self showAlertViewwithTitle:#"Oops..." andMessage:#"Please pair with a device"];
}
}
- (void)postData{
//post stress signal to server
}
- (void)showAlertViewwithTitle:(NSString *)title andMessage:(NSString *)message{
WKAlertAction *act = [WKAlertAction actionWithTitle:#"OK" style:WKAlertActionStyleCancel handler:^(void){}];
NSArray *actions = #[act];
[self presentAlertControllerWithTitle:title message:message preferredStyle:WKAlertControllerStyleAlert actions:actions];
}
So, just succeede in sending the message and also pair devices but now i don't receive the sent dictionary in the iOS app.
You need to activate your WCSession in both the WatchKit App Extension and in the iPhone application. Based on the code you've shown us, it does not appear you are activating it in your iPhone application.
Add the following to your iPhone application:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([WCSession isSupported]) {
WCSession* session = [WCSession defaultSession];
session.delegate = self;
[session activateSession];
}
...
You should then be able to receive the message via your existing session:didReceiveMessage:replyHandler: method.

WCSession on Apple Watch not work properly

I have XCode 7, iPhone6 with iOS 9.1, Apple Watch with WatchOS 2.0 (now I update to 2.0.1)
I try to make communication between Watch and iPhone.
On iPhone I init my singleton
- (instancetype)init {
self = [super init];
if (self.isConnectivityAvailable) {
session = [WCSession defaultSession];
session.delegate = self;
[session activateSession];
}
return self;
}
- (BOOL)isConnectivityAvailable {
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"9.0")) {
return [WCSession isSupported];
} else {
return NO;
}
}
in AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//custom code
(void)[AppConnectivityHandler instance]; //start App connectivity with Apple Watch
return YES;
}
And it is all good
I process message like that
- (void)session:(WCSession *)session didReceiveMessage:(NSDictionary<NSString *,id> *)message replyHandler:(void (^)(NSDictionary<NSString *,id> * _Nonnull))replyHandler {
LOG(#"receive message");
NSString *request = message[kRequestKey];
__block NSDictionary *reply = #{};
dispatch_sync(dispatch_get_main_queue(), ^{
if ([request isEqualToString:kRequestDayInfo]) {
//formirate reply dictionary
}
});
LOG(#"send reply");
replyHandler(reply);
}
On my Watch I start load when called function in my main interface controller
- (void)willActivate {
[super willActivate];
if ([WatchConnectivityHandler instance].isConnectivityAvailable) {
[[WatchConnectivityHandler instance] loadDayInfoWithCompletion:^(NSError * _Nullable error, WatchDayInfo * _Nullable dayInfo) {
//code
}];
} else {
//error
}
}
My watch singleton
+ (nonnull instancetype)instance {
static WatchConnectivityHandler *instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [WatchConnectivityHandler new];
});
return instance;
}
- (instancetype)init {
self = [super init];
if (self.isConnectivityAvailable) {
session = [WCSession defaultSession];
session.delegate = self;
[session activateSession];
}
return self;
}
- (BOOL)isConnectivityAvailable {
return [WCSession isSupported];
}
- (void)loadDayInfoWithCompletion:(void(^ _Nonnull)( NSError * _Nullable error, WatchDayInfo * _Nullable dayInfo))completion {
[session sendMessage:#{kRequestKey : kRequestDayInfo} replyHandler:^(NSDictionary<NSString *,id> * _Nonnull replyMessage) {
NSLog(#"reply");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(#"%#", replyMessage);
//custom code
completion(nil, /*custom object*/);
});
} errorHandler:^(NSError * _Nonnull error) {
NSLog(#"error");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(#"%#", error);
completion(error, nil);
});
}];
}
So it work fine in first time and I get reply. But then I start a lot of errors like
Error Domain=WCErrorDomain Code=7007 "WatchConnectivity session on paired device is not reachable."
Error Domain=WCErrorDomain Code=7014 "Payload could not be delivered."
I test on Watch, and it is often problem to get reply form my iPhone, it wait a long. But on iPhone I test, that when it get message from Watch, it very quick send reply, but I don't see that reply on Watch.
I need update my info every time when watch start my app. What the problem? Maybe I use not properly functions?
Use transeruserinfo method instead of sendmessage and use didreceiveuserinfo method instead of didreceiveapplicationcontext.

Is it possible to institute a timeout for SKStoreProductViewController loadProductWithParameters?

I'm currently calling storeViewController loadProductWithParameters via dispatch_async . Is it possible to set a timeout value so it only tries to fetch the results for X seconds and then gives up?
I implemented my own timeout by using with the class method below instead of calling loadProductWithParameters directly. It times out thanks to a dispatch_after and __block variable.
+ (void)loadProductViewControllerWithTimeout:(NSTimeInterval)timeout
storeKitViewController:(SKStoreProductViewController *)storeKitViewController
parameters:(NSDictionary *)parameters
completionHandler:(void (^)(BOOL result, NSError *error))completionHandler {
__block BOOL hasReturnedOrTimedOut = NO;
[storeKitViewController loadProductWithParameters:parameters completionBlock:^(BOOL result, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (!hasReturnedOrTimedOut) {
hasReturnedOrTimedOut = YES;
if (completionHandler) completionHandler(result, error);
}
});
}];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (!hasReturnedOrTimedOut) {
hasReturnedOrTimedOut = YES;
if (completionHandler) completionHandler(NO, nil); // Or add your own error instead of |nil|.
}
});
}
My latest app update got rejected by Apple because loadProductWithParameters never called its completionBlock and stopped my users from buying songs on iTunes... Hope this helps.
I have acomplished it like so:
__block BOOL timeoutOrFinish = NO;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(30 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if(!timeoutOrFinish) {
timeoutOrFinish = YES;
[self dismissAndShowError];
}
});
[storeViewController loadProductWithParameters:parameters completionBlock:^(BOOL result, NSError * _Nullable error) {
if(timeoutOrFinish) {
return;
}
timeoutOrFinish = YES;
//[[NetworkManager sharedManager] showNetworkActivityIndicator:NO];
if(error) {
[self dismissAndShowError];
}
}];
[self.view.window.rootViewController presentViewController:storeViewController animated:YES completion:nil];
where dismissAndShowError method runs dismissViewControllerAnimated and shows alert with an error.
Basically, you have a separate timer (30 seconds in my case) that switches a flag. After that time, if store has still not been loaded, I close it and display an error. Otherwise, completion is called (on cancel, finish and error) and handles all actions according to the status.

Resources