Deep Linking¶
Deep linking is the use of an URL that takes users directly to specific content in your app and optionally provides data to that content. The ability can be broken down into a few specific actions:
- Define the URI link and its data
- Create an intent filter in the manifest
- Receive the intent, parse the data, and load the configuration
Define the URI Link¶
The URI link contains the android application package name, the attributes specified in the intent filter, and the configuration data used by the referenced configuration provider.
The following HTML encoded generic link and intent filter shows an example of a deep link and the format of the data used by a Configuration Loader provider:
<a href="android-app://<Android_Application_PackageName>/<Scheme>/<Host>/<Path>?data={"<ConfigurationProviderID>":[{"<ProviderSpecific_DataKey>":"<ProviderSpecific_DataKey_Value>"}]}"> Launch DeepLink application</a>
<intent-filter>
<data android:scheme="https" android:host="<Host>"/>
<data android:scheme="<Scheme>" android:host="<Path>" android:pathPrefix="/"/>
...
</intent-filter>
The following HTML encoded link and intent filter shows a real example of a deep link and the data used by the Discovery Service Configuration Provider:
<a href="android-app://com.myApp.package/myApp/www.example.com/configuration?data={"com.sap.configuration.provider.discoveryservice":[{"email_address":"user@ad9a3f3b6.pilot.sapmobileplace.com"}]}"> Launch DeepLink application</a>
<intent-filter>
<data android:scheme="https" android:host="www.example.com" />
<data android:scheme="myApp" android:host="configuration" android:pathPrefix="/"/>
...
</intent-filter>
The above examples, show how you should specify the attributes contained within the intent filter in the manifest file. The elements in the deep link URI and the intent filter must match.
Create an Intent Filter in the Manifest¶
To enable the link handling for the app content, you must include an intent filter in your manifest file that contains the following elements and attribute values:
-
<action>
- Include theACTION_VIEW
intent action so that the intent filter can be reached from Google Search. -
<category>
- Include theBROWSABLE
category. It is required in order for the intent filter to be accessible from a web browser. Also, include theDEFAULT
category. This allows the app to respond to implicit intents. -
<data>
- Include the<data>
tags, each of which represents a URI format that resolves to an activity. Each<data>
tag includes the following attributes:android:scheme
,android:host
, andandroid:pathPrefix
. This was previously covered in the section above since its data must correspond with the values defined by the deep link URI.
The following XML snippet shows how you might specify an intent filter in your manifest for deep linking:
<activity
android:name=".DeepLinkActivity">
<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="https" android:host="www.example.com" />
<data android:scheme="myApp" android:host="configuration" android:pathPrefix="/"/>
</intent-filter>
</activity>
Receive the Intent, Parse the URI Data, and Load the Configuration¶
In the following example, the deep link data is extracted from the intent. The data must be URI-decoded to translate any
escape sequences into their corresponding special characters. The deep link data is then parsed into a UserInput
object using the static method parseJson
of the UserInput
s class. This UserInput
object is then passed to the
ConfigurationLoader
constructor. Please refer to Creating a
ConfigurationLoader
for more details on constructing a
configuration loader.
Finally, the loadConfiguration
method is called to produce the configuration data. It accomplishes this by passing the
input data to the associated provider enabling it to retrieve and load the configuration accordingly.
The second parameter of the parseJson
method is a list of supported provider identifiers. If one or more custom
providers is created then the ProviderIdentifier
class is extended and a new list containing the custom provider
identifiers must be passed to parseJson
.
public class DeepLinkActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Extract the deep link data from the intent
String deepLinkData;
Intent thisIntent = getIntent();
Uri intentUri = thisIntent.getData();
if (intentUri != null) {
try {
String data = URLDecoder.decode(intentUri.toString(), "UTF-8");
deepLinkData = data.split("data=")[1];
} catch (Exception e) {}
}
// Parse the deep link data into a User Inputs object - Note: JSON Provider input is ignored
UserInputs initialUserInputs = UserInputs.parseJson(deepLinkData, ProviderIdentifier.KNOWN_PROVIDERS);
// Instantiate the Configuration Loader with initial inputs extracted from the deep link
ConfigurationLoader configurationLoader = new ConfigurationLoader(
getApplicationContext(),
configurationLoaderCallback,
initialUserInputs
);
configurationLoader.loadConfiguration();
}
}
class DeepLinkActivity : AppCompatActivity() {
override fun onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
// Extract the deep link data from the intent
val deeplinkData: String? = when(intent.data != null) {
true -> {
val data = URLDecoder.decode(this.toString(), "UTF-8")
data.split("data=".toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()[1]
}
false -> null
}
// Parse the deep link data into a User Inputs object - Note: JSON Provider input is ignored
val initialUserInputs = UserInputs.parseJson(deepLinkData, ProviderIdentifier.KNOWN_PROVIDERS)
// Instantiate the Configuration Loader with initial inputs extracted from the deep link
val configurationLoader = ConfigurationLoader(applicationContext, configurationLoaderCallback, initialUserInputs)
.apply {
loadConfiguration()
}
}
}
Providing deep link data to the JSON provider is a security risk, and is therefore excluded by default. If it is desired
to supply JSON input in a case where the risk has been mitigated, then this default can be overridden simply by passing
an empty exclusion list to parseJson
. This is shown in the following example:
// Parse the deep link data into a User Inputs object - Note: JSON Provider input is allowed
UserInputs initialUserInputs = UserInputs.parseJson(
deepLinkData,
ProviderIdentifier.KNOWN_PROVIDERS,
new ProviderIdentifier[] {}
);
val initialUserInputs = UserInputs.parseJson(
deepLinkData,
ProviderIdentifier.KNOWN_PROVIDERS,
arrayOf<ProviderIdentifier>()
)