Introduction to the

The word “Link” refers to a Link that leads directly to an APP. This Link is often used for APP pull, cross-app launch, push notification launch, etc.

process

AS in fact, there have been detailed steps to use the analysis, here for everyone to popularize

shift

add URL intent filters

Create a URL

Add logic to handle the intent

Select the entry activity to start with Applink. When you’re done, AS is automatically modified in two places, one is AndroidManifest

 <activity android:name=".TestActivity">
            <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="http"
                    android:host="geyan.getui.com" />
            </intent-filter>
        </activity>
Copy the code

There’s a data tag here, and we can make a bold guess that maybe this applink is an implicit startup. Another change

    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        // ATTENTION: This was auto-generated to handle app links.
        Intent appLinkIntent = getIntent();
        String appLinkAction = appLinkIntent.getAction();
        Uri appLinkData = appLinkIntent.getData();
    }
Copy the code

The value of applink is the url link configured earlier. This is used to receive data. No more details.

Associate website

This step is the most critical. You need to generate a JSON file according to the APP certificate. When installing the APP, you will go to the Internet for verification. Select your online certificate and click Generate to get an assetlinks.json file, which you will need to place in the directory specified by the server

[{
  "relation": ["delegate_permission/common.handle_all_urls"]."target": {
    "namespace": "android_app"."package_name": "com.lenny.myapplication"."sha256_cert_fingerprints":
    ["E7:E8:47:2A:E1:BF:63:F7:A3:F8:D1:A5:E1:A3:4A:47:88:0F:B5:F3:EA:68:3F:5C:D8:BC:0B:BA:3E:C2:D2:61"]}}]Copy the code

The parameter sha256_cert_fingerprints can be fetched using the keytool command and I won’t say more here. Upload the file to your address /.well-know/statements/json. Android will only check this file when the app is installed to avoid having to link every app request to the network. If you can contact us at yourdomain.com/.well-known… If you see this file (replace it with your own domain name), then the server configuration is successful. This file is currently available over HTTP, but in the M final version it can only be authenticated over HTTPS. Make sure your Web site supports HTTPS requests. If multiple apps need to be configured for one host, assetlinks.json adds the information about multiple apps. If you need to configure multiple hosts for an app, you should set assetlinks.json under the.well-known name of each host. Have you ever wondered if the suffix of the URL should be /.well-know/statements/json? We’ll talk about it later, but I won’t go into detail here. In the end, we essentially just get a URL. Most of the time, we will concatenate some parameters in the URL, such as

https://yourdomain.com/products/123?coupon=save90
Copy the code

Among them, / products / 123? Coupon =save90 is the path we filled in in the second step. You can use notifications, you can use SMS, or you can use ADB emulation, which I’m going to use to save the trouble

adb shell am start
-W -a android.intent.action.VIEW
-d "https://yourdomain.com/products/123?coupon=save90"[package]Copy the code

Using this command will automatically open the APP. If the web-app association file exists on yourdomain.com.

The principle of

These are simple, as well, here is something deep, should not only know the use, also need to know why so to use, otherwise and salted fish have what differentiation.

The domain name is configured in the data tag of the activity. If the applink is implicitly launched, the application will be installed using assetlinks.json. If the url meets the criteria, it will be saved locally. When clicking on the URL in webView or SMS, the system will automatically match the domain name in the local library. If the match fails, it will be automatically regarded as deeplink’s connection. When you first install the APP, you will ask for the domain name below the data tag, and you will ask for the domain name you obtained. The installation process of an APk is extremely complex and involves a lot of underlying knowledge. I won’t go into detail here, just find the installPackageLI method of the PackageManagerService, the entry point to verify APPLink.

PackageMmanagerService.class

private void installPackageLI(InstallArgs args, PackageInstalledInfo res) { final int installFlags = args.installFlags; <! - start validation applink - > startIntentFilterVerifications (args. User. GetIdentifier (), replace, PKG); . } private void startIntentFilterVerifications(int userId, boolean replacing, PackageParser.Package pkg) { ... mHandler.removeMessages(START_INTENT_FILTER_VERIFICATIONS); final Message msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS); msg.obj = new IFVerificationParams(pkg, replacing, userId, verifierUid); mHandler.sendMessage(msg); }Copy the code

You can see that a handler message is sent as START_INTENT_FILTER_VERIFICATIONS, In the run method of handle verifyIntentFiltersIfNeeded will then call again.

private void verifyIntentFiltersIfNeeded(int userId, int verifierUid, boolean replacing, PackageParser.Package pkg) { ... <! -- Check whether an AppLink is set for an Activity --> Final Boolean hasDomainURLs = hasDomainURLs(PKG);if(! hasDomainURLs) {if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
                    "No domain URLs, so no need to verify any IntentFilter!");
            return; } <! -- Autoverigy --> Boolean needToVerify =false;
        for (PackageParser.Activity a : pkg.activities) {
            for(ActivityIntentInfo filter : a.intents) { <! --needsVerification whether to set autoverify -->if (filter.needsVerification() && needsNetworkVerificationLPr(filter)) {
                    needToVerify = true;
                    break; }}} <! -- If there is information about the Activity and scheme that need to be verified -->if (needToVerify) {
            final int verificationId = mIntentFilterVerificationToken++;
            for (PackageParser.Activity a : pkg.activities) {
                for (ActivityIntentInfo filter : a.intents) {
                    if (filter.handlesWebUris(true) && needsNetworkVerificationLPr(filter)) {
                        if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG,
                                "Verification needed for IntentFilter:"+ filter.toString()); mIntentFilterVerifier.addOneIntentFilterVerification( verifierUid, userId, verificationId, filter, packageName); count++; }}}}} <! -- Start validation -->if(count > 0) { mIntentFilterVerifier.startVerifications(userId); }}Copy the code

Check, collect and verify APPLink, mainly check whether the scheme is HTTP/HTTPS, and whether there are parameters with flags of Intent.ACTION_DEFAULT and Intent.ACTION_VIEW, and then enable authentication

PMS#IntentVerifierProxy.class

public void startVerifications(int userId) {
        ...
            sendVerificationRequest(userId, verificationId, ivs);
        }
        mCurrentIntentFilterVerifications.clear();
    }

    private void sendVerificationRequest(int userId, int verificationId,
            IntentFilterVerificationState ivs) {

        Intent verificationIntent = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION);
        verificationIntent.putExtra(
                PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_ID,
                verificationId);
        verificationIntent.putExtra(
                PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_URI_SCHEME,
                getDefaultScheme());
        verificationIntent.putExtra(
                PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_HOSTS,
                ivs.getHostsString());
        verificationIntent.putExtra(
                PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_PACKAGE_NAME,
                ivs.getPackageName());
        verificationIntent.setComponent(mIntentFilterVerifierComponent);
        verificationIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);

        UserHandle user = new UserHandle(userId);
        mContext.sendBroadcastAsUser(verificationIntent, user);
    }
Copy the code

The realization of the Android now is by sending a radio to verify, that is to say, this is an asynchronous process, validation is take request (network), sent will be IntentFilterVerificationReceiver receives the broadcast. This class will start DirectStatementService again, and it will call DirectStatementRetriever from within the service. In the retrieveStatementFromUrl method of this class is where the network is actually requested

DirectStatementRetriever.class

  @Override
    public Result retrieveStatements(AbstractAsset source) throws AssociationServiceException {
        if (source instanceof AndroidAppAsset) {
            return retrieveFromAndroid((AndroidAppAsset) source);
        } else if (source instanceof WebAsset) {
            return retrieveFromWeb((WebAsset) source);
        } else {
            throw new AssociationServiceException("Namespace is not supported.");
        }
    }
  private Result retrieveFromWeb(WebAsset asset)
            throws AssociationServiceException {
        return retrieveStatementFromUrl(computeAssociationJsonUrl(asset), MAX_INCLUDE_LEVEL, asset);
    }
    private String computeAssociationJsonUrl(WebAsset asset) {
        try {
            return new URL(asset.getScheme(), asset.getDomain(), asset.getPort(),
                    WELL_KNOWN_STATEMENT_PATH)
                    .toExternalForm();
        } catch (MalformedURLException e) {
            throw new AssertionError("Invalid domain name in database.");
        }
    }
private Result retrieveStatementFromUrl(String urlString, int maxIncludeLevel,
                                        AbstractAsset source)
        throws AssociationServiceException {
    List<Statement> statements = new ArrayList<Statement>();
    if (maxIncludeLevel < 0) {
        return Result.create(statements, DO_NOT_CACHE_RESULT);
    }

    WebContent webContent;
    try {
        URL url = new URL(urlString);
        if(! source.followInsecureInclude() && ! url.getProtocol().toLowerCase().equals("https")) {
            returnResult.create(statements, DO_NOT_CACHE_RESULT); } <! - request access through the network configuration - > the webContent = mUrlFetcher. GetWebContentFromUrlWithRetry (url, HTTP_CONTENT_SIZE_LIMIT_IN_BYTES, HTTP_CONNECTION_TIMEOUT_MILLIS, HTTP_CONNECTION_BACKOFF_MILLIS, HTTP_CONNECTION_RETRY); } catch (IOException | InterruptedException e) {return Result.create(statements, DO_NOT_CACHE_RESULT);
    }
    
    try {
        ParsedStatement result = StatementParser
                .parseStatementList(webContent.getContent(), source); statements.addAll(result.getStatements()); <! -- If there is a one-to-many situation, or "proxy" is set, loop to get the configuration -->for (String delegate : result.getDelegates()) {
            statements.addAll(
                    retrieveStatementFromUrl(delegate, maxIncludeLevel - 1, source) .getStatements()); } <! -- Send results -->return Result.create(statements, webContent.getExpireTimeMillis());
    } catch (JSONException | IOException e) {
        returnResult.create(statements, DO_NOT_CACHE_RESULT); }}Copy the code

That’s pretty much the end of the story here, but it’s essentially an HTTPURLConnection to make a request. /.well-known/assetlinks.json (); /.well-known/assetlinks.json (); / / known_statement_path ()

    private static final String WELL_KNOWN_STATEMENT_PATH = "/.well-known/assetlinks.json";

Copy the code

disadvantages

  1. After configuring app support for App Links, only users running Android M will be able to work properly. Users of previous Android versions couldn’t just click on the link to go to the app, but instead went back to the browser’s Web page.
  2. To use App Links developers have to maintain a website associated with their App. This is a little difficult for small developers who don’t have the ability to maintain a website for their App, but they still want to get traffic through web Links.
  3. Ink domain name is not friendly in the test found that the domestic manufacturers of. Ink domain name is not friendly, many are supported. Com domain name, but do not support. Ink domain name.
models version Identify ink Recognize COM
millet MI6 Android 8.0 MIUI 9.5 no is
millet MI5 Android 7.0 MIUI 9.5 no is
meizu PRO 7 Android 7.0 Flyme 6.1.3.1a no is
samsung The S8 Android 7.0 Is that box is
huawei HonorV10 Android 8.0 EMUI 8.0 is is
Oppo R11s Android 7.1.1 ColorOS 3.2 is is
oppo A59s Android 5.1 ColorOS 3.0 Yes, you can’t jump to the app Yes, you can’t jump to the app
vivo X6Plus A Android 5.0.2 Funtouch OS_2.5 no is
vivo 767 Android 6.0 Funtouch OS_2.6 Yes, you can’t jump to the app Yes, you can’t jump to the app
vivo X9 Android 7.1.1 Funtouch OS_3.1 Yes, you can’t jump to the app Yes, you can’t jump to the app

reference

1. The official document: developer.android.com/studio/writ…

Author: Haha will

Industry frontier, mobile development, data modeling and other dry content, all in the public account: Gepu Technology Institute