Application Call via Custom URL Scheme
The Complete Tutorial on iOS/iPhone Custom URL Schemes
Note: Since the introduction of custom URL schemes, this post has consistently been the top read content on the blog. Although much is the same, there are a few nuances that have changed. This is a re-write of the original post, updated for the latest iOS and Xcode versions.
One of the coolest features of the iPhone/iOS SDK is an application’s ability to “bind” itself to a custom URL scheme and for that scheme to be used to launch the application from either a browser or from another application.
Registering a Custom URL Scheme
The first step is to create a custom URL scheme – start by locating and clicking on the project info.plist in the Xcode Project Navigator. With the plist displayed in the right pane, right click on the list and select Add Row:
From the list presented scroll down and select URL types.
Open the directional arrow and you’ll see Item 0, a dictionary entry. Expand Item 0 and you will see URL Identifier, a string object. This string is the name for the custom URL scheme you are defining. It’s recommended to ensure uniqueness of the name that you reverse domain name such as com.yourCompany.yourApp.
Tap on Item 0 and add a new row, select URL Schemes from the drop-down and tap Enter to complete the row insert.
Notice URL Schemes is an array, allowing multiple URL schemes to be defined for an application.
Expand the array and tap on Item 0. This is where you will define the name for the custom URL scheme. Enter just the name, do not append :// – for instance, if you enter iOSDevApp, your custom url will be iOSDevApp://
Here is how the complete definition looks at this point:
Although I appreciate Xcode’s intention when using descriptive names, I find it helpful to see the actual keys created. Here’s a handy trick, right-click on the plist and select Show Raw Keys/Values, the output will look as follows:
There’s another output format that also has merit, XML, as it’s much easier to see the structure of the dictionary and the nested array and its entries. Tap the plist and this time choose Open As – Source Code:
Calling Custom URL Scheme from Safari
With the URL scheme defined, we can run a quick test to verify the app can be called as expected using the URL. Before we do that, I’ll create a barebones UI so we can identify the app with the custom URL. The app contains nothing more than a UILabel with the text “App With Custom URL.”
Using the simulator, here’s how to call the app:
– Run the application from within Xcode
– Once installed, the custom URL scheme will now be registered
– Close the app via the Hardware menu in simulator and choose Home
– Start Safari
– Enter the URL scheme defined previously in the browser address bar (see below)
– Once installed, the custom URL scheme will now be registered
– Close the app via the Hardware menu in simulator and choose Home
– Start Safari
– Enter the URL scheme defined previously in the browser address bar (see below)
At this point Safari will close and the app will be brought to the foreground. Congratulations, you’ve just called an iPhone application using a custom URL scheme!
Calling Custom URL Scheme from Another iPhone App
Let’s take a look at how to call the custom URL scheme from another iPhone application. Again, I’ve created a very simple iPhone application with nothing more than a UILabel and a UIButton – the former shows a message that this is the app that will call another app via a custom URL scheme, the button starts that process.
The code inside the buttonPressed manages the URL processing:
- (void)buttonPressed:(UIButton *)button
{
NSString *customURL = @"iOSDevTips://";
if ([[UIApplication sharedApplication]
canOpenURL:[NSURL URLWithString:customURL]])
{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:customURL]];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"URL error"
message:[NSString stringWithFormat:
@"No custom URL defined for %@", customURL]
delegate:self cancelButtonTitle:@"Ok"
otherButtonTitles:nil];
[alert show];
}
}
Passing Parameters To App Via Custom URL Scheme
Chances are you’ll need to pass parameters into the application with the custom URL definition. Let’s look at how we can do this with.
The NSURL class which is the basis for calling from one app to another conforms to the (Relative Uniform Resource Locators). Therefore the same URL formatting you may be familiar with for web-based content will apply here as well.
In the application with the custom URL scheme, the app delegate must implement the method with the signature below:
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary *)options
The trick to passing in parameters from one app to another is via the URL. For example, assume we are using the following custom URL scheme and want to pass in a value for a ‘token’ and a flag indicating registration state, we could create URL as follows:
NSString *customURL = @"iOSDevTips://?token=123abct®istered=1";
As in web development, the string ?token=123abct®istered=1 is known as the query string.
As in web development, the string ?token=123abct®istered=1 is known as the query string.
Inside the app delegate of the app being called (the app with the custom URL), the code to retrieve the parameters would be as follows:
****Write Code in Appdelegate
// Declare
@property (nonatomic, strong) NSURL *launchedURL;
// Write in didFinishLaunchingWithOptions Method
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
self.launchedURL = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey];
NSLog(@"%@", self.launchedURL);
return YES;
}
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary *)options {
if ([[url scheme] isEqualToString:@"siaevents"])
{
NSLog(@"url recieved: %@", url);
NSLog(@"query string: %@", [url query]);
NSLog(@"host: %@", [url host]);
NSLog(@"url path: %@", [url path]);
NSDictionary *dict = [self parseQueryString:[url query]];
NSLog(@"query dict: %@", dict);
NSURL *openUrl = url;
if (!openUrl)
{
return NO;
}
return [self openLink:openUrl];
}
}
- (NSDictionary *)parseQueryString:(NSString *)query {
NSMutableDictionary *dict = [[[NSMutableDictionary alloc] initWithCapacity:6] autorelease];
NSArray *pairs = [query componentsSeparatedByString:@"&"];
for (NSString *pair in pairs) {
NSArray *elements = [pair componentsSeparatedByString:@"="];
NSString *key = [[elements objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *val = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[dict setObject:val forKey:key];
}
return dict;
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
if (self.launchedURL) {
[self openLink:self.launchedURL];
self.launchedURL = nil;
}
}
- (BOOL)openLink:(NSURL *)urlLink
{
NSLog(@"%@",urlLink);
return YES ;
}
Update your info.plist file
The very first step to add deep linking support for our app will be to update our info.plist file. You can update the file by following the instructions in my video or open it as a source file and paste the following code snipped either at the top of the document(right after the opening <dict> tag) or at the bottom of your document(right before the </dict></plist> tags).
Replace the value of CFBundleURLSchemes which is in my case “SwiftDeveloperBlogDeepLink” with a unique deep link url scheme that will make sense for your app. Just remember to make it short and unique. And replace the value of CFBundleURLName with a value of Bundle Identifier of your app. You can check the video on how I do it.
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>SwiftDeveloperBlogDeepLink</string>
</array>
<key>CFBundleURLName</key>
<string>com.kargopolov.CodeExamples</string>
</dict>
</array>
Replace the value of CFBundleURLSchemes which is in my case “SwiftDeveloperBlogDeepLink” with a unique deep link url scheme that will make sense for your app. Just remember to make it short and unique. And replace the value of CFBundleURLName with a value of Bundle Identifier of your app. You can check the video on how I do it.
Update AppDelegate.swift file
For your app to be able to listen to custom url schema clicks you will need to add the below function to your AppDelegate.swift file. This function is part of UIApplicationDelegate protocol.
To compile the code snippet about you will need to either create a new ViewController named “InnerPageViewController” and assign it an Identifier “InnerPageViewController” or edit this code to use a name of one of your existing view controllers.
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
print("url \(url)")
print("url host :\(url.host!)")
print("url path :\(url.path)")
let urlPath : String = url.path as String!
let urlHost : String = url.host as String!
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
if(urlHost != "swiftdeveloperblog.com")
{
print("Host is not correct")
return false
}
if(urlPath == "/inner"){
let innerPage: InnerPageViewController = mainStoryboard.instantiateViewController(withIdentifier: "InnerPageViewController") as! InnerPageViewController
self.window?.rootViewController = innerPage
} else if (urlPath == "/about"){
}
self.window?.makeKeyAndVisible()
return true
}
To compile the code snippet about you will need to either create a new ViewController named “InnerPageViewController” and assign it an Identifier “InnerPageViewController” or edit this code to use a name of one of your existing view controllers.
And this is basically it. For the code about to work and open the inner page of my app when user clicks on a link in mobile browser, I need to create a link that will look like this:
- <a href="SwiftDevelop://swiftdeveloper/inner">Click here to switch to app</a>
where
- “SwiftDevelop” – is the custom URL Scheme name,
- “swiftdeveloper” – is the host name, which can be any other name you can come up with and use in the app’s business logic,
- “inner” – is the custom schema url path which I used to compare and make decision which page to open for user.
No comments:
Post a Comment