Somehow when running our e2e detox tests we always wait for some synchronization to finish (If we disable it and wait manually it works).
I tried removing all animation but somehow there is still something running.
The log shows the following:
detox info Sync App State: undefined
detox info Sync Dispatch Queue: com.apple.main-thread
detox verb ws send: {"type":"currentStatus","params":{},"messageId":21}
detox verb ws onMessage: {"type":"currentStatusResult","messageId":21,"params":{"state":"busy","resources":[{"name":"App State","info":{"elements":["<UIViewController: 0x7fdc1351bf50>"],"appState":"Waiting for window's root view controller's view to appear."}},{"name":"Dispatch Queue","info":{"queue":"<OS_dispatch_queue_main: com.apple.main-thread[0x112beadc0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = com.apple.root.default-qos.overcommit[0x112bec300], width = 0x1, state = 0x001ffe9e00000400, dirty, max qos 6, in-flight = 0, thread = 0x403 }>","prettyPrint":"com.apple.main-thread"}}],"messageId":21}}
detox verb ws
detox info Sync App State: undefined
detox info Sync Dispatch Queue: com.apple.main-thread
detox verb ws send: {"type":"currentStatus","params":{},"messageId":22}
detox verb ws onMessage: {"type":"currentStatusResult","messageId":22,"params":{"state":"busy","resources":[{"name":"App State","info":{"elements":["<UIViewController: 0x7fdc1351bf50>"],"appState":"Waiting for window's root view controller's view to appear."}},{"name":"Dispatch Queue","info":{"queue":"<OS_dispatch_queue_main: com.apple.main-thread[0x112beadc0] = { xref = -2147483648, ref = -2147483648, sref = 1, target = com.apple.root.default-qos.overcommit[0x112bec300], width = 0x1, state = 0x001ffe9e00000400, dirty, max qos 6, in-flight = 0, thread = 0x403 }>","prettyPrint":"com.apple.main-thread"}}],"messageId":22}}
Any help where this issue is coming from highly appreciated
[Update 2018/04/18]:
Just to clarify:
The render function of my app component is like that:
render() {
const {
isOnboardingVisible,
} = this.props;
if (isOnboardingVisible) {
return (
<View>
<Onboarding onPressButton={this.props.onOnboardingViewed} />
</View>
);
}
return <LoginScreen statusBarHidden {!!this.props.notification} />;
};
The test navigates from the onboarding to the login screen by changing the isOnboardingVisible prop and gets stuck in the login screen waiting for an element to be visible (it's clearly visible on the screen).
If I remove the onboarding screen and directly start the test on the login screen the test works.
Here is our AppDelegate.m like requested in the comments:
#import "AppDelegate.h"
#import <CodePush/CodePush.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <BugsnagReactNative/BugsnagReactNative.h>
#import <Fabric/Fabric.h>
#import <Crashlytics/Crashlytics.h>
#import <react-native-branch/RNBranch.h>
#import "OneSignalConfig.h"
#import <React/RCTPushNotificationManager.h>
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#implementation AppDelegate
#synthesize oneSignal = _oneSignal;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"GoogleService-Info" ofType:#"plist"];
NSDictionary *plistDict = [NSDictionary dictionaryWithContentsOfFile:filePath];
[GIDSignIn sharedInstance].clientID = [plistDict objectForKey:#"CLIENT_ID"];
#ifdef FREEWORK_DEBUG
[RNBranch useTestInstance];
#endif
#ifdef FREEWORK_EDGE
[RNBranch useTestInstance];
#endif
#ifdef FREEWORK_STAGING
[RNBranch useTestInstance];
#endif
[RNBranch initSessionWithLaunchOptions:launchOptions isReferrable:YES];
NSURL *jsCodeLocation;
#ifdef DEBUG
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:#"index" fallbackResource:nil];
#else
jsCodeLocation = [CodePush bundleURL];
#endif
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:#"Freework"
initialProperties:nil
launchOptions:launchOptions];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
OneSignalConfig* config = [[OneSignalConfig alloc] init];
self.oneSignal = [[RCTOneSignal alloc] initWithLaunchOptions:launchOptions
appId: [config getOneSignalAppId]
settings:#{kOSSettingsKeyAutoPrompt: #false}];
[[FBSDKApplicationDelegate sharedInstance] application:application
didFinishLaunchingWithOptions:launchOptions];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
[BugsnagReactNative start];
[Fabric with:#[[Crashlytics class]]];
return YES;
}
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
BOOL handled = [[GIDSignIn sharedInstance] handleURL:url
sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]
annotation:options[UIApplicationOpenURLOptionsAnnotationKey]];
return handled;
}
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
if (![RNBranch.branch application:application openURL:url sourceApplication:sourceApplication annotation:annotation]) {
if ([LinkedinSwiftHelper shouldHandleUrl:url]) {
return [LinkedinSwiftHelper application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
} else if ([[GIDSignIn sharedInstance] handleURL:url
sourceApplication:sourceApplication
annotation:annotation]) {
return YES;
} else if( [url.absoluteString rangeOfString: #"fb" ].location != NSNotFound ) {
return [[FBSDKApplicationDelegate sharedInstance] application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
} else {
}
}
return YES;
}
// Respond to Universal Links
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler {
return [RNBranch continueUserActivity:userActivity];
} // Required to register for notifications
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
[RCTPushNotificationManager didRegisterUserNotificationSettings:notificationSettings];
}
// Required for the register event.
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
[RCTPushNotificationManager 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
{
[RCTPushNotificationManager didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
// Required for the registrationError event.
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
[RCTPushNotificationManager didFailToRegisterForRemoteNotificationsWithError:error];
}
// Required for the localNotification event.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
[RCTPushNotificationManager didReceiveLocalNotification:notification];
}
#end
Related
How do you import files to your app on ios13?
Previously I could download a txt file in Safari and chose Copy to (app) and I would catch this in the app delegate open Url delegate. Doesn't work anymore.
The Copy To is still there in Safari, but it just dismissed Safari and nothing happens.
-- Edit:
Sorry, I was a bit unclear.
Previously, when downloading a file through another app (like Safari), the user could select to open this file in my app by tapping "Copy To (app)".
I would then catch this copy request through the appdelegate:
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
[...]
}
This delegate is not called in iOS13, only iOS12 and below.
I have tried finding a way to catch the "Copy to" request from other apps to no avail. There seems to be a new way of handling these things through a SceneDelegate?
In projects having SceneDelegate.swift file, should implement scene:openURLContext method.
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
print(#function)
print(URLContexts)
}
Output:
scene(_:openURLContexts:)
[
<UIOpenURLContext: 0x282fbca20;
URL: file:///private/var/mobile/Containers/Data/Application/A644621B-BD6C-443B-A9D1-A212EA59EE2E/Documents/Inbox/file.pdf;
options: <UISceneOpenURLOptions: 0x2823112c0;
sourceApp: (null);
annotation: (null);
openInPlace: NO>>
]
Reference: Migration from AppDelegate to SceneDelegate
Version for Objective C.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSURL *url = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey];
[[CommonController sharedInstance] handleExternalUrl: url];
return YES;
}
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options
{
NSLog(#"application openURL: %#", url);
return [[CommonController sharedInstance] handleExternalUrl: url];
}
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions API_AVAILABLE(ios(13.0)){
NSSet *c = connectionOptions.URLContexts;
if(c && [c count] > 0)
{
NSURL *url = ((UIOpenURLContext*)[[c allObjects] firstObject]).URL;
[[CommonController sharedInstance] handleExternalUrl: url];
}
}
- (void)scene:(UIScene *)scene openURLContexts:(nonnull NSSet<UIOpenURLContext *> *)URLContexts
API_AVAILABLE(ios(13.0)){
NSURL *url = [[URLContexts allObjects] firstObject].URL;
[[CommonController sharedInstance] handleExternalUrl: url];
}
I am attempting to install react-native-navigation and am following the instructions from https://wix.github.io/react-native-navigation/#/docs/Installing at the section for editing ios files. The instructions tell me to edit the AppDelegate.m. The instructions tell me to add this code and the end result should look like this.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... }
and the end result should look like this
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <ReactNativeNavigation/ReactNativeNavigation.h>
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:#"index" fallbackResource:nil];
[ReactNativeNavigation bootstrap:jsCodeLocation launchOptions:launchOptions];
return YES;
}
#end
but my AppDelegate.m looks nothing like this? instead it looks like this...
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
return [RCTLinkingManager application:application openURL:url
sourceApplication:sourceApplication annotation:annotation];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:#"planzu"
initialProperties:nil];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:#"index" fallbackResource:nil];
#else
return [[NSBundle mainBundle] URLForResource:#"main" withExtension:#"jsbundle"];
#endif
}
#end
how should I proceed? Am I supposed to eliminate the top and bottom methods? or just replace the event call 'didFinishLaunchingWithOptions'?
You should just modify your AppDelegate's didFinishLaunchingWithOptions method to be as mentioned in the RNN documentation. This is the entry point for RNN and it replaces the usual react-native setup of creating the bridge and the root-view.
You can leave the other two methods (openURL and sourceURLForBridge) as is.
when app in not in background mode ,inactive mode and app is completely closed. than how to detect is their any notification using application's delegate "didFinishLaunchingWithOption" method. i have searched a lot about it but not get anything. please help .
Thanks
Below methods is used for notifiaction
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (notification)
{
}
}
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
NSString *token = [[[[deviceToken description]
stringByReplacingOccurrencesOfString:#"<"withString:#""]
stringByReplacingOccurrencesOfString:#">" withString:#""]
stringByReplacingOccurrencesOfString: #" " withString: #""];
NSLog(#"Token:%#",token);
}
//app is forground this method will access
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
}
//need to on teh background fetch option in info plist
//app is background state this below mthod will call while notification receives
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSLog(#"Background mode working%#",userInfo);
if([userInfo[#"aps"][#"content-available"] intValue]== 1) //it's the silent notification when recive preferences and text messages
{
}
}
//handling interactive notification
- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forLocalNotification:(nonnull UILocalNotification *)notification completionHandler:(nonnull void (^)())completionHandler {
}
You can do this in the didFinishLaunchingWithOption method
let launchedFromRemoteNotification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] != nil
You can get Notification in the didFinishLaunchingWithOption in this way :
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notification) {
NSLog(#"app recieved notification from remote%#",notification);
}else{
NSLog(#"app did not recieve notification");
}
}
Try this it may help you.
If the App was terminated and is starting again, you can detect the Remote Notification only if the App is being launched because the user tapped on the remote notification in the notifications tray.
You can detect it in the didFinishLaunchingWithOptions method
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSDictionary *notificationDict = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notificationDict) {
//Your App received a remote notification
}else{
//Your App did not receive a remote notification
}
}
I would call a NSURLSessionDataTask in appDelegate when the app is open from mail, so in this function
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
I tried but doesn't work, why??
I need to get a query from this function
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
NSURLComponents *components = [[NSURLComponents alloc] init];
components.query = [url query];
BOOL confirmRegistration = NO;
NSString *userToken;
for (NSURLQueryItem *queryItem in components.queryItems) {
if ([queryItem.name isEqualToString:#"userToken"])
{
userToken = queryItem.value;
}
else if ([queryItem.name isEqualToString:#"registrationType"])
{
if ([queryItem.value isEqualToString:#"confirmRegistration"])
{
confirmRegistration = YES;
}
}
}
//la app รจ stata aperta con la mail di conferma registrazione
if (confirmRegistration)
{
NSDictionary* userInfo = #{#"userToken": userToken};
[[NSNotificationCenter defaultCenter] postNotificationName:#"confirmRegistration" object:nil userInfo:userInfo];
}
return YES;
}
Thank you
When Application is opened from anywhere, the application:didFinishLaunchingWithOptions: is called.
There you check the launchingOptions to see what triggered the opening for application.
For instance, if application is opened using push notifications. You do something like below.
if let userInfo = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? [NSObject : AnyObject] {
self.application(application, didReceiveRemoteNotification: userInfo)
}
You can check the keys which you get when you open the application from Mail.
UPDATE
There are keys like UIApplicationLaunchOptionsSourceApplicationKey and UIApplicationLaunchOptionsURLKey which you can print or compare to what triggered the application launch and then start your work.
When you open your application from Mail then print the following and use it to compare and start your work.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
print(launchOptions?[UIApplicationLaunchOptionsSourceApplicationKey])
print(launchOptions?[UIApplicationLaunchOptionsURLKey])
return true
}
I have a problem implementing - (BOOL)application:openURL and using UIDocumentInteractionController for exporting PDF file from an application to another.
(1) Target application does nothing but just display URL of the imported PDF file (in a label).
here is the code in AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[ViewController alloc] initWithText:#"No file is imported."];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication: (NSString *)sourceApplication annotation:(id)annotation
{
if (url != nil)
{
[self.viewController handleOpenURL:url];
return YES;
}
else
{
[self.viewController handleOpenURL:[NSURL fileURLWithPath:#"AppDelegate.h"]];
return NO;
}
}
Method "handleOpenURL" just take the url and put in a label in the view controller and show an alert:
- (void)handleOpenURL:(NSURL *)fileURL
{
_text = [fileURL absoluteString];
self.lblText.text = _text;
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:#"Alert" message:_text delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil];
[alert show];
}
(2) In source application, I simply use UIDocumentInteractionController to list "Open In" options (my target application appears well in the list)
Here is the code:
_docInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:attachmentFile]];
_docInteractionController.delegate = self;
_docInteractionController.UTI = [_extensionUTIs objectForKey:[[attachmentFile pathExtension] lowercaseString]];
BOOL opened = [_docInteractionController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:NO];
(3) Problem:
- When I select the target application (from "Open In" list), simulator switches from source application to target application okay, but looks like application:openURL method is not invoked because the label keeps as initial (No file is imported.) and no alert view shows up.
Please advise me what could be wrong here ?
Thanks in advance.
I used these two methods for facebook integration to handle openURL...its working fine.
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
return [ [[HIFacebookConnect sharedGameObject] facebook] handleOpenURL:url];
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [[[HIFacebookConnect sharedGameObject] facebook] handleOpenURL:url];
}
Just want to mark my question as answered because I have already found the glitch.
Update: It was my fault when not including full file path when initiating UIDocumentInteractionController object.