I have an extension and a container app.I open the container app with the method
[[self extensionContext] openURL:[NSURL URLWithString:#"customURLScheme://"] completionHandler:nil];
from extension via custom URL scheme but I don't know how to run some code in the container app as soon as it launches...??
In another words I'm trying to use the URL scheme just to open the app and then call some method from container app.
In your containing app's AppDelegate, you need to implement the method application:open:options: and do whatever is required in there.
The containing app gets the full URL that was used to open it, so you can use the URL to encode different operations to perform.
Related
I'd like to write a test for my iOS app that verifies the correct screen content is shown when the app is launched from a custom registered URL scheme.
For example, a user receives an email with a link to myapp://action1/1234. When they tap on this link, my app is launched and the screen displays "1234".
In didFinishLaunchingWithOptions my AppDelegate checks to see if launchOptions?[UIApplicationLaunchOptionsURLKey] exists and takes appropriate action.
How do I write a UI test so that the app launchOptions dictionary contains the expected URL when the app is launched?
You can make this work by leveraging launchEnvironment on XCUIApplication in combination with a few lines of custom code in your target app. Basically you would set a custom launch environment variable for this test, and in your app you would check for that variable and handle it the same way you would handle the existence of the particular UIApplicationLaunchOptionsURLKey you're expecting.
In your app you can check that value via NSProcessInfo.processInfo.environment which returns a dictionary of the environment variables.
(Take note that the default XCTestCase template in Xcode 7 includes a call to XCUIApplication -launch in setup which will terminate any previously running instance, and launch a new instance by default.)
Edit: wanted to add, I've written a little bit more about this in an article on Xcode 7 UI Testing Tips, in case it's helpful.
I just get started with WatchKit and I'm trying to do this (if I'm not wrong, it is possible to do): I'd like the WatchKit Extension to ask the containing app for requesting some data to a web service, and then return the service response to the Extension to update the WatchKit App interface accordingly.
As I read in Apple Watch Programming Guide, yo can call the openParentApplication:reply: method in the WatchKit Extension to request something to its containing app, and then the application:handleWatchKitExtensionRequest:reply: method in the AppDelegate of the containing app should be called. Once this method called, I need to perform the service request, wait for its response, and then send it back to the Extension.
However, when I run the WatchKit App scheme in the simulator, the openParentApplication:reply: method is called, but a breakpoint within the application:handleWatchKitExtensionRequest:reply: is not reached. So I'm not even able to test if I can correctly perform the web service request and get its response back.
What could I be missing? Should I configure somehow the schema to reach breakpoints in the containing app as well? Is it needed to declare some kind of background feature for this?
Thanks in advance
I just answered a very similar question here which will allow you to open the iOS app from the Watch Extension and getting a reply back.
In order to debug the iOS app while running the Watch Extension, you should follow the steps explained here.
I have a share extension implemented for iOS8. The service uses OAuth to authenticate. The login info I use for the extension is shared with the container app.
The problem is:
When I am in the extension, then app switch to the container app and logout, and then app switch back to the host app containing the extension - How do I detect that the extension has just re-appeared? The extension is relying on certain information to be present in the shared DB between the container app and the extension, however, that data is removed when the app logs out.
I have tried registering for various "app notifications" such as UIApplicationDidBecomeActiveNotification. However, as expected, these aren't called for extensions.
How can I detect when the state of the extension changes such that I can make my extension more robust when it reappears?
The viewDidAppear:animated: method of your main view controller class should be called every time you reenter your extension. When you are about to leave, viewWillDisappear:animated: should be called.
See
NSExtensionContext.h
iOS 8.2 added a number of notifications to use for extensions:
NSExtensionHostDidBecomeActiveNotification
NSExtensionHostDidEnterBackgroundNotification
NSExtensionHostWillEnterForegroundNotification
NSExtensionHostWillResignActiveNotification
Here is what I have tried that has NOT worked:
Using openURL to attempt to open the containing app
Here is what I have thought of that wouldn't work:
Using local notifications to provide a link to the containing app (creating the local notification from the extension)
Here are options I am considering:
Using a UIDocumentInteractionController and a custom file extension type to provide a link to my containing app (and my containing app only)
Starting a "fake" NSURL session to get the following functionality: In iOS, if your extension isn’t running when a background task completes, the system launches your containing app in the background and calls the application:handleEventsForBackgroundURLSession:completionHandler: app delegate method.
The UIDocumentInteractionController is confirmed to work in Xcode 6.5, but the flow is kind of wonky. The NSURL thing should work as well, but it's also a bit fishy. Does anyone have any other ideas of getting my containing app to open from a share extension, or an idea to communicate with it from a share extension?
I have confirmed that the NSURLSession way (second bullet under the "considering" options above) indeed does work. I'm still working out some kinks, but here are the basics. Using this method, you can indeed open your app from a share extension.
This method requires 3 main steps, as follows:
Make a background NSURLSession in a Share Extension.
Start a download task.
Call exit(0).
Make sure the thing you are downloading takes long enough so that the extension terminates before the download task finishes.
NSString *address = #"https://googledrive.com/host/0B5zObXR9UzgmbFpob2J5eXpjNXc/file3m";
self.mySession = [self configureMySession];
NSURL *url = [NSURL URLWithString:address];
NSURLSessionTask *myTask = [self.mySession downloadTaskWithURL:url];
[myTask resume];
exit(0);
Then, in your containing application's UIApplicationDelegate class, implement the
application:handleEventsForBackgroundURLSession:completionHandler:
method. This method gets called when the download task finishes after your extension has been terminated. Then, in this method, you can call
[[UIApplication sharedApplication] openURL:url];
or do some other stuff in your containing app.
The main problem with this method is that there is a delay between the time when the extension terminates and the time when the the containing app starts up. The main advantage of this method over the UIDocumentInteractionController method is that no extra user interaction is needed. More details will come as I continue to experiment.
How programmatically restart an iPhone app in iOS?
I find this way http://writeitstudios.com/david/?p=54
But may be something simple.
The only way I know to do this is not ideal, but it works.
First, your app has to opt out of background execution (multitasking) The app has to quit when exited, not run as a background task. This is done with the plist key UIApplicationExitsOnSuspend.
Second, your app needs to register a custom URL scheme that can be used to launch the app.
Third, you need a web page hosted somewhere that when loaded will redirect to your app's custom URL scheme.
Forth, the user needs an active Internet connection.
To exit and restart, call UIApplication openURL on your hosted redirecting web page. Your app will exit and safari will launch and load your page. The page will redirect Safari to your custom URL scheme, prompting Safari to internally call openURL, causing iOS to launch your app.
my post that you linked to is referring to a Cocoa Application, not the iOS. On the iOS, you can quit an application (but Apple doesn't like this) by using exit(0); but I don't recommend that. You cannot restart iPhone apps though.
Unless you're developing for jailbroken devices, Apple won't even allow you to programatically terminate your app. So restarting the device is out of the question.
Your AppDelegate instance has a method
(void)applicationDidBecomeActive:(UIApplication *)application
{
}
In here, you can put logic to figure out if the app should restart, or continue doing whatever it was doing. For example you can have a BOOL variable appMustRestart that is false at first but gets triggered as true whenever something happens in your app that you'd like the next time to be a fresh relaunch.
if (appMustRestart)
{
[self resetVars]; // call a method that resets all your vars to initial settings
// INSERT CODE HERE TO TRANSFER FOCUS TO INITIAL VIEWCONTROLLER
}