IBM Worklight 6.2 ChallengeHandler submitFailure: doesn't behave as expected - ios

I am using Worklight 6.2 iOS native framework. I have implemented a custom MyChallengeHandler that subclasses ChallengeHandler, and logging in:
[[WLClient sharedInstance] login:#"SomeRealm" withDelegate:LoginListener];
In ChallengeHandler I can submit success, which calls onSuccess: in LoginListener:
[self submitSuccess:response];
However, I can't submit failure, which I was expecting to call onFailure: in LoginListener. In fact, it looks like there is no effect when calling submitFailure: and onFailure: never gets called in LoginListener.
Also, I don't see a declaration of submitFailure: in WL ChallengeHandler header, it is available only in BaseChallengeHandler.
My main point is, currently it looks like the LoginListener onFailure: method is never called, but there are cases when the handleChallenge: should fail. And LoginListener should get released.
Is this a known issue in Worklight, is there any workaround?
Update 1:
Just found a similar problem for JS client API, which isn't useful for native:
Adapter procedure call, reporting an authentication failure
Update 2:
This might be important. I am using Adapter authentication, but in the IBM example there is submitLoginForm:, maybe my issue is for Adapter authentication only.
[self submitAdapterAuthentication:invocationData options:nil]

It's a big vague so far but I will write some possibilities I think of. Let me know if any help, and I will update my answer.
1) Your code above says you use the class ChallangeHandler. I am not sure if the typo is only in StackOverflow or in your real code as well, but the class is ChallengeHandler, with a e.
Same for handleChallange instead of handleChallenge.
2) Did you register your challenge handler somewhere?
[[WLClient sharedInstance] registerChallengeHandler:[[MyChallengeHandler alloc] initWithViewController:self] ];
3) Do you ever get to the success of your LoginListener? And of your challenge handler?
You are correct that the documentation does not mentiond submitFailure - I will look into that.
However in code I wrote, I was able to use this without problems.
#implementation MyChallengeHandler
//...
-(void) onSuccess:(WLResponse *)response {
NSLog(#"inside challenge success");
[self.vc.navigationController popViewControllerAnimated:YES];
[self submitSuccess:response];
}
-(void) onFailure:(WLFailResponse *)response {
NSLog(#"inside challenge failure");
[self submitFailure:response];
}

Related

How to detect when Crashlytics has NOT created a report

I have two code paths that needs to execute on app launch:
1. When Crashlytics detects a report from the last run
2. When it is a clean launch, ie, no crash report was detected.
Crashlytics provides (and recommends) that this method be used to detect crashes:
- (void) crashlyticsDidDetectReportForLastExecution:(CLSReport *)report
but the documentation specifically says that the method is not called synchronously during initialization. So while I can use this for detecting case #1, I don't think it is possible to use the same method to detect case #2 without possibly introducing a race condition.
As far as I can tell, the current framework does not expose any method to check for the existence of a report, either in Crashlytics.h or CLSReport.h. If it did, I could check for the existence of a crash report before the framework initializes.
Suggestions?
Solution proposed by Mike (from Fabric)
Mike -- I'm used to assuming that delegate methods and callbacks cannot be assumed to happen synchronously, or on the same thread. You seem to be saying that I can/should make that assumption here, so that this (psdeudocode) would work:
(in AppDelegate)
- (void)crashlyticsDidDetectReportForLastExecution:(CLSReport *)report completionHandler:(void (^)(BOOL))completionHandler {
self.HadCrash = YES;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
completionHandler(YES);
}];
}
(In AppDelegate didFinishLaunching)
crashlytics.delegate = self;
[crashlytics init]; // presumably if the delegate method IS going to be called, it will be called here.
if (!HadCrash)
{ // do "no crash" stuff here }
Mike from Fabric here, there are two methods that can be used to know about a crash that happened.
1) - (void)crashlyticsDidDetectReportForLastExecution:(CLSReport *)report;
This method has the following restrictions:
It is not called synchronously during initialization
It does not give you the ability to prevent the report from being submitted
The report object itself is immutable
The most important benefits are that the ability to report crashes is not affected in any way.
2) - (void)crashlyticsDidDetectReportForLastExecution:(CLSReport *)report completionHandler:(void (^)(BOOL submit))completionHandler;
This is called synchronously when the last execution of the app ended in a crash.
You can then take whatever action you want to take, but the report will not be sent unless the completionHandler is called with YES passed in. If NO is passed in then the call will be finished, but no report would be sent.
Here's a sample implementation from the docs:
- (void)crashlyticsDidDetectReportForLastExecution:(CLSReport *)report completionHandler:(void (^)(BOOL))completionHandler {
// Use this opportunity to take synchronous action on a crash. See Crashlytics.h for
// details and implications.
// Maybe consult NSUserDefaults or show a UI prompt.
// But, make ABSOLUTELY SURE you invoke completionHandler, as the SDK
// will not submit the report until you do. You can do this from any
// thread, but that's optional. If you want, you can just call the
// completionHandler and return.
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
completionHandler(YES);
}];
}
I think that addresses the question, but let me know if I missed something.

CallKit:No sound when I use WebRTC

Our project uses WebRTC for VOIP calls and it works fine before accessing the CallKit framework. But when I tried to access the CallKit framework, there was a situation where neither side could hear each other's speech. When I removed CallKit, everything returned to normal.
CallKit's answer button is the same function as the original answer button in the project.
And what amazed me was that it was not necessary to hear no sound. Sometimes everything is normal, but sometimes there will be problems. Well, the probability of a problem is greater.
I found the following flowchart, I suspect the problem lies in the order of function calls. But I do not know how WebRTC corresponds to the functions in the diagram.
In addition, I am curious whether socket instability will cause the CallKit framework to work abnormally
Please forgive me English is not good, but this problem has been haunted me for several days, I do not know where exactly a problem, is not where the conflict with the CallKit framework?
Hope you can help me, thank you very much!
Few steps need to be done to connect webrtc and callkit in proper way:
First of all, you have to use the RTCAudioTrack and add the RTCAudioSession for handling the audio. Old legacy RTCAudioSession added directly into RTCPeerConnection works but it's not prefered a way to do that.
Second thing is to use manualAudio. When app is booted you should change useManualAudio flag on RTCAudioSession:
RTCAudioSession.sharedSession().useManualAudio = true
which gives you possibility to postpone the audio until CallKit informs that audio session was activated, so inside the ProviderDelegate you should implement following method:
(void)provider:(CXProvider *)provider didActivateAudioSession:(AVAudioSession *)audioSession
RTCAudioSession.sharedSession().didActivecated(audioSession)
RTCAudioSession.sharedSession().isAudioEnabled = true
and for second audio delegate method don't forget to add:
(void)provider:(CXProvider *)provider didDeactivateAudioSession:(AVAudioSession *)audioSession
RTCAudioSession.sharedSession().didDeactivecated(audioSession)
RTCAudioSession.sharedSession().isAudioEnabled = false
Apple suggests us to wait till the Connection gets established and then fulfill the performAnswerAction. Below is the source
Apple Suggestion for Call Kit Documentation
If the recipient of a call answers before the app establishes a connection to your server, don't fulfill the CXAnswerCallAction object sent to the provider:performAnswerCallAction: method of your delegate immediately. Instead, wait until you establish a connection and then fulfill the object. While it waits for your app to fulfill the request, the incoming call interface lets the user know that the call is connecting, but not yet ready.
So we need to wait for a second or two before we fulfill the action in performAnswerCallAction
In the end, I solved the problem, but I still do not understand why it can be solved.Below is my solution:
First of all, I delay the call of "fulfill" by 1 second (note that this time can not be less than 1 second)
- (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action {
if (self.delegate && [self.delegate respondsToSelector:#selector(callKitManager:refreshCurrentCallStatus:)]) {
[self.delegate callKitManager:self refreshCurrentCallStatus:EUCCallKitStatusAnswerAccept];
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[action fulfill];
});}
Second, I also delayed my network request call by one second (here longer than the previous one)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.peerConnection offerForConstraints:[self offerConstraintsRestartIce:NO] completionHandler:^(RTCSessionDescription * _Nullable sdp, NSError * _Nullable error) {
[self peerConnection:self.peerConnection didCreateSessionDescription:sdp error:error];
}];
});
In this way, my problem is solved.
If you know why this can solve this problem, please comment on me, thank you!

Objective c Thread 1 signal SIGSTOP app crashes

I'm trying to track down an error that appears to be definitely a timing issue. I have an application that uses a Universal Framework. When the process is complete in the framework an NSNotification is sent back to the application. We have recently added a third party framework to our framework. Now, while the methods for the third party framework are being executed, as execution returns to our framework I receive the following error in the Console Output:
Assertion failed: (exclusive), function assert_locked, file ../dep/include/boost/boost_1_55_0/boost/thread/pthread/shared_mutex.hpp, line 51.
But I'm not sure that is the ultimate issue, because our framework continues to execute and the NSNotification is sent back to the application. Right after the Notification is sent and execution returns to the calling method (or the method call) in our framework I see a warning on the executing thread. Then, execution continues back to the original calling method and the warning goes away.
Here's the weird part. If I step through the code very slowly, it might just work. If I'm not slow enough I get the SIGSTOP and the code never returns to the UI. If I'm too fast, I get a SIGABRT.
I've been trying to find the exact issue using Instuments. This answer to a similar question backed up my suspicion that this is a timing issue. I think the boost assert_locked Assertion might have something to do with this.
My code is pretty boring but I know you want to see it, so here it is:
- (void)generateImageTemplates:(UIImage *)src
{
int result = 0;
cv::Mat image = *(cv::Mat*)[self cvMatFromUIImage:src];
user = IEngine_InitUser();
int userID=0;
result = IEngine_AddFingerprintRAW(user, UNKNOWN, image.data, image.size().width, image.size().height);
result = IEngine_RegisterUser(user, &userID);
[[NSNotificationCenter defaultCenter] postNotificationName:#"InnovatricsComplete" object:self];
}
If you're wondering what result is, it's an error code. So far these have all come back equal to 0. Meaning no errors. I'll work on handling these errors once I can get a successful return to the UI without crashing.
Control returns to the method call:
- (void)generateImageTemplates:(UIImage *)processedImage
{
[self.captureCommand generateImageTemplates:processedImage];
}
Control returns to the method call in the application View Controller:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 0){
[self clearPressed:self.clearButton];
} else {
[self.cameraVC generateImageTemplates:self.processedImage];
}
}
Finally, the NSNotification callback code:
- (void)onInnovatricsComplete:(NSNotification *)note
{
[self.cameraVC willMoveToParentViewController:nil];
[self.cameraVC.view removeFromSuperview];
[self.cameraVC removeFromParentViewController];
}
I warned you it was pretty boring!
I'm completely stumped! Though I continue to surf the internet for clues, is there anybody out there who can help me resolve this issue?
Thank you.
Here are some screenshots (in reverse order):
look at NSUinteger’s answer in How to know where crash for postNotificationName:object:userInfo
the listener might be deallocated before it recieves the notification.

iOS writing unit test involving Mknetworkkit

I tried to run MKNetworkKit in my project, it seemed to be fine. I then created a unit test project and call the engine to make some requests (using the MkNetworkOperation). I get no apparent error but the completionhandler block never get called, and so was the errorblock.
I examined my unit test setup, there's no apparent error, and the whole thing "ran". I just dont get any response. If i switch and do this in my main project, it works.
I have also added all the necessary framework to the unit test project.
One thing i notice is that Reachability message get printed out for the case that worked, but nothing for the case that didnt.
Any clue as to whats going on?
Sounds like you need a semaphore or something similar to block the execution until the request returns. Unit tests run until the end of the method. If they hit the end of the method without an error, they were successful. Since your using MKNetworkKit, the server request is async, so the end of the method is hit before the request is complete. I found a helper class to help with unit tests. I'll try to find it again and link to it with some sample code.
Found it: http://www.touch-code-magazine.com/unit-testing-for-blocks-based-apis/
So it's been a while since I wrote these tests. I'm pretty sure this will work, but you might have to tweak it.
-(void)tests {
//setup
NSString *key = #"myTestKey";
//test
STAssertNoThrow(
[API resetPassword:#"fakeemail#this.net callback:^(NSDictionary *result) {
STAssertNotNil(result, #"reset pass response was nil"]);
[[TestSemaphor sharedInstance] lift:key];
} error:^(NSDictionary *error) {
STFail(#"reset password failed: %#", error.description);
[[TestSemaphor sharedInstance] lift:key];
}], #"reset password failed");
[[TestSemaphor sharedInstance] waitForKey:key];
}

Google Analytics on iOS returning NO on dispatch, no debug output

In trying to implement the Google Analytics SDK for iOS, I've run into two brick walls.
The first one is that after executing this code in application:DidFinishLaunchingWithOptions:
[[GANTracker sharedTracker] startTrackerWithAccountID:#"UA-XXXXXXX-YY"
dispatchPeriod:10
delegate:self];
[[GANTracker sharedTracker] setDebug:YES];
.. and then trying to track anything or call dispatch, no debug messages are logged whatsoever. I've added NSLog lines before and after tracking calls and the code is definitely being reached.
Secondly, when I do try and do a manual dispatch, it returns NO. All the other issues I've seen online are where dispatch returns YES but it's somehow not going through properly. What does one do if dispatch actually returns NO?
I've tried adding an NSError * reference to the track methods and those actually succeed (no error, function returns YES). But the events are definitely not being periodically dispatched, since we're seeing nothing on the GA account more than 24 hours later.
EDIT: I've also got NSLog calls in both of the delegate methods (hitDispatched: and trackerDispatchDidComplete:eventsDispatched:eventsFailedDispatch:), and neither of those are being called either.
i think you should check this to delegate method of GANTracker
- (void)trackerDispatchDidComplete:(GANTracker *)tracker
eventsDispatched:(NSUInteger)hitsDispatched
eventsFailedDispatch:(NSUInteger)hitsFailedDispatch{
//print or check number of events failed or success
}
//Delegate is set to 'nil' instead of class instance which implements the delegate methods.
[[GANTracker sharedTracker] startTrackerWithAccountID:#"UA-XXXXXXX-YY"
dispatchPeriod:10
delegate:nil];
In your case, assuming that UIApplicationDelegate may be implementing GANTrackerDelegate, the message call should set delegate as ' self '.
Cheers!! Amar.
Possibly the dispatch is relying on the calling thread's run loop - Is it possible you are running this from a secondary thread, one which might not exist by the time the dispatch is suppose to call you back?
You've not enabled dryRun have you? Double check with:
[[GANTracker sharedTracker] setDryRun:NO];
Also try dispatchSynchronous, it'll block as it's sending but might help with if things aren't on the same threads:
[[GANTracker sharedTracker] dispatchSynchronous];
Just've checked it from scratch, dispatch perfectly worked meaning
a) your device is somehow different (i still have unsolved crashes on the particular iPad's 3 from Apple tester's unresolved, so it wouldn't be a huge surprise)
b) your code is somehow different - and that's much easier for you to fix.
For the a) there's no advice but to test it against all the devices you might get, for the b) i could only say what worked for me:
downloaded 1.4 SDK here
got Google sample projects with git clone https://code.google.com/p/google-mobile-dev.analytics-end-to-end/
configured final/AnalyticsSample to launch, changed the source slightly
(trackEvent::::: were called from sample, app was restarted manually as there's zero time period requiring dispatch call)
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[GANTracker sharedTracker] startTrackerWithAccountID:kGANAccountId
dispatchPeriod:0
delegate:self];
NSLog(#"Dispatch%#", [[GANTracker sharedTracker] dispatch] ? #"ed Successfully": #" Failed");
[self.window addSubview:tabBarController.view];
[self.window makeKeyAndVisible];
return YES;
}
That's it, log says Dispatched Successfully, worth trying i guess.
cough
I'd misspelled the #define to start the tracker object in my app delegate. Other files were spelled correctly, hence the logging statements showing up, but when I tried to log just before the tracker was started it didn't show.
Oops. Well, at least there's a decent troubleshooting post for Google Analytics on SO now!

Resources