Skip to main content
Version: Next

Linking

Using Custom URL Schemes

Applications communicate with each other by calling and sending data. iOS and Android have different ways to handle this. In this guide, we will show you how to do it.

URL Schemes in Smartface Run-on-Device App

You can't use custom URL Schemes on Smartface Run-on-Device App (emulator). The Smartface app has its own URL Scheme as "smartface-emulator://" for iOS and Android.

Defining Custom Schemes in iOS

One of the useful features of iOS is the ability to bind URL schemes to applications. Using schemes is the only way of calling another app. Multiple schemes can be defined for an app. Built-in apps has their own schemes like "http, mailto, tel". To handle these schemes, refer here. If your URL includes a scheme that is identical to one of the schemes defined by Apple, the app provided by Apple will take precedence.
Apple also has a note about the case when two different apps use the same scheme:

Multiple Apps with the Same URL Scheme in iOS

If more than one third-party app registers to handle the same URL scheme, there is currently no process for determining which app will be given that scheme.

You should define URL Schemes on config/iOS/info.plist. You can find more information about URL Schemes on iOS Guides and Samples.

XML
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myscheme-one</string>
</array>
</dict>
</array>

Defining Custom Schemes and Intents in Android

In Android you can easily define URL Schemes and Intents in config/Android/AndroidManifest.xml. For more information, you can follow Developer Android.

Multiple Apps with the Same URL Scheme/Intent in Android

If there is an application installed with the same scheme with yours, Android will open the default application if there is no chooser dialog requested. You can use Linking.openURL for calling applications with the chooser dialog.

Android URL Scheme/Intent Registration

In Android, in order for a URL scheme/intent to be registered for an app, the user should launch the application once.

XML
<activity android:name=".A"
android:label="${ApplicationName}"
... >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myscheme-one" />
</intent-filter>
....
</activity>

Using Multiple URL Schemes

Using multiple URL Schemes is possible on Smartface Native Framework.\ For iOS, you can define additional schemes with on config/iOS/info.plist :

XML
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myscheme-one</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myscheme-two</string>
<string>myscheme-three</string>
</array>
</dict>
</array>

For Android, you can define additional schemes/intents with :

XML
<activity android:name=".A"
android:label="${ApplicationName}"
... >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myscheme-one" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myscheme-two" />
</intent-filter>
....
</activity>

You can detect which URL Scheme called from Application.onApplicationCallReceived with the e.url parameter of the event for iOS and Android.

Deep Linking

For more information, you can check mobiledeeplinking.org

Inter-app communication

Inter-app communication is a communication between applications with data support. In order to perform Inter-app communication, we use the Linking.openURL method. You can launch another application and also pass data to it.

How to Use Inter-app communication between Smartface Applications?

First of all, you need to have two different app projects which are using different bundle identifiers and URL Schemes. ( such as : io.smartface.app1 , io.smartface.app2 and myscheme-one, myscheme-two)
We will call application two from application one by using their URL Schemes.

Defining URL Schemes

You can check Using Custom URL Schemes for communicating between applications with URL Scheme.

For the first application that we are going to create, let's use the code block below:

TypeScript
import PageSampleDesign from "generated/pages/pageSample";
import { Route, Router } from "@smartface/router";
import System from "@smartface/native/device/system";
import Button from "@smartface/native/ui/button";
import Label from "@smartface/native/ui/label";
import Application from "@smartface/native/application";

//You should create new Page from UI-Editor and extend with it.
export default class Sample extends PageSampleDesign {
myButton: Button;
myLabel: Label;
constructor(private router?: Router, private route?: Route) {
super({});
}

// The page design has been made from the code for better
// showcase purposes. As a best practice, remove this and
// use WYSIWYG editor to style your pages.
centerizeTheChildrenLayout() {
this.dispatch({
type: "updateUserStyle",
userStyle: {
flexProps: {
flexDirection: "COLUMN",
justifyContent: "CENTER",
alignItems: "CENTER",
},
},
});
}

onShow() {
super.onShow();
const { headerBar } = System.OS === System.OSType.ANDROID ? this : this.parentController;
Application.statusBar.visible = true;
headerBar.visible = true;
}

onLoad() {
super.onLoad();
this.centerizeTheChildrenLayout();

this.myLabel = new Label({
text: "Smartface Application 1",
});

this.myButton = new Button({
text: "Call Application 2",
onPress: function () {
Linking.openURL({
uriScheme: "myscheme-two://",
data: { origin: "Smartface_App1" },
onSuccess: function () {
alert("Application call completed");
},
onFailure: function () {
alert("Application call failed");
},
isShowChooser: true,
chooserTitle: "Choose an Application",
});
},
});

this.addChild(this.myLabel, "myLabel", ".sf-label", {
height: 100,
width: 250,
marginBottom: 50,
flexProps: {
alignSelf: "CENTER",
},
});

this.addChild(this.myButton, "myButton", ".sf-button", {
height: 100,
width: 250,
flexProps: {
alignSelf: "CENTER",
},
});

Application.onApplicationCallReceived = function (e): void {
alert({
title: "Application Call Received",
message: JSON.stringify(e),
});
};
}
}

For the second application, let's use the following page code:

TypeScript
import PageSampleDesign from "generated/pages/pageSample";
import { Route, Router } from "@smartface/router";
import System from "@smartface/native/device/system";
import Button from "@smartface/native/ui/button";
import Label from "@smartface/native/ui/label";
import Application from "@smartface/native/application";

//You should create new Page from UI-Editor and extend with it.
export default class Sample extends PageSampleDesign {
myButton: Button;
myLabel: Label;
constructor(private router?: Router, private route?: Route) {
super({});
}

// The page design has been made from the code for better
// showcase purposes. As a best practice, remove this and
// use WYSIWYG editor to style your pages.
centerizeTheChildrenLayout() {
this.dispatch({
type: "updateUserStyle",
userStyle: {
flexProps: {
flexDirection: "COLUMN",
justifyContent: "CENTER",
alignItems: "CENTER",
},
},
});
}

onShow() {
super.onShow();
const { headerBar } = System.OS === System.OSType.ANDROID ? this : this.parentController;
Application.statusBar.visible = true;
headerBar.visible = true;
}

onLoad() {
super.onLoad();
this.centerizeTheChildrenLayout();

this.myLabel = new Label({
text: "Smartface Application 2",
});

this.myButton = new Button({
text: "Call Application 2'",
onPress: function () {
Linking.openURL({
uriScheme: "myscheme-two://",
data: { origin: "Smartface_App2" },
onSuccess: function () {
alert("Application call completed");
},
onFailure: function () {
alert("Application call failed");
},
isShowChooser: true,
chooserTitle: "Choose an Application",
});
},
});

this.addChild(this.myLabel, "myLabel", ".sf-label", {
height: 100,
width: 250,
marginBottom: 50,
flexProps: {
alignSelf: "CENTER",
},
});

this.addChild(this.myButton, "myButton", ".sf-button", {
height: 100,
width: 250,
flexProps: {
alignSelf: "CENTER",
},
});

Application.onApplicationCallReceived = function (e): void {
alert({
title: "Application Call Received",
message: JSON.stringify(e),
});
};
}
}
Android onApplicationCallReceived Behavior

onApplicationCallReceived will be triggered when the application started from the System Launcher. For this reason, if data does not contain a key that you can handle, you should ignore this call.