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.
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:
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.
<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.
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.
In Android, in order for a URL scheme/intent to be registered for an app, the user should launch the application once.
<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 :
<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 :
<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.
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.
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:
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:
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),
});
};
}
}
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.