Exclude few Urls from deeplinking

2020-02-09 04:44发布

问题:

I could successfully implement deeplinking of app using following filter in the intent-filter in my Manifest:

   <data  android:host="myhost.com"
    android:pathPrefix="/v"
    android:scheme="http" />

Eg. My Urls are:

 http://myhost.com/v/login1.php?id=123&name=abc&type=a
 http://myhost.com/v/login1.php?id=123&name=abc&type=b

I want to exclude

http://myhost.com/v/login1.php?id=123&name=abc&type=c

Now I want to exclude a few Urls which have same prefix. Is it possible or Do I need to explicitly specify all urls with android:path ? If so, how to deal with values of query parameters?

回答1:

Unfortunately we can't exclude any certain url, since Android doesn't provide that option.

The best practice is to give as precise pathPrefix as possible.

Specify only host without any pathPrefix is OK, as long as all actions carried out by the application makes sense. But if there is any link which should do something specific while the application could not handle, then it should let the web service handle it properly. In this case, whitelisting everything is not a good idea, if your web service can do more than your application.

Some people like matching only host in manifest, then handle different cases in code. You never know what unexpected url could be captured, if it really make senses to handle it by "else" condition. Better, do it carefully, only list the pathPrefix that we are sure about.

Back to your case, most of the time, I believe that application is able to handle the url if it's only different in query parameter. Because it belongs to the same action (by API's route handler), just different results. Only when the whole routing is different, you should treat it differently by giving the right pathPrefix.

So the valid example could be:

// To handle:
http://myhost.com/v/login1?id=123&name=abc&type=a
// To exclude:
http://myhost.com/v/login2?id=123&name=abc&type=a

Then in AndroidManifest.xml:

<data android:scheme="http"
      android:host="myhost.com"
      android:pathPrefix="/v/login1" />

Note: In case you stumble upon noindex.xml, that is for App Indexing, not for deep linking exclusion.



回答2:

You could let the app decide whether to let the browser handle the URL

@Override
protected void onNewIntent(Intent intent) {
    if (intent.getData().getQueryParameter("type").equals("c")) {
        forwardToBrowser(intent);
    }
    else {
        handleIntent(intent);
    }
};

// from https://stackoverflow.com/a/23268821/3221253
private void forwardToBrowser(Intent i) {
    Intent intent = new Intent();
    intent.setAction(android.content.Intent.ACTION_VIEW);
    intent.setDataAndType(i.getData(), i.getType());
    List<ResolveInfo> activities = getPackageManager().queryIntentActivities(intent, 0);
    ArrayList<Intent> targetIntents = new ArrayList<Intent>();
    String thisPackageName = getApplicationContext().getPackageName();
    for (ResolveInfo currentInfo : activities) {
        String packageName = currentInfo.activityInfo.packageName;
        if (!thisPackageName.equals(packageName)) {
            Intent targetIntent = new Intent(android.content.Intent.ACTION_VIEW);
            targetIntent.setDataAndType(intent.getData(),intent.getType());
            targetIntent.setPackage(intent.getPackage());
            targetIntent.setComponent(new ComponentName(packageName, currentInfo.activityInfo.name));
            targetIntents.add(targetIntent);
        }
    }
    if(targetIntents.size() > 0) {
        Intent chooserIntent = Intent.createChooser(targetIntents.remove(0), "Open with");
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[] {}));
        startActivity(chooserIntent);
        finish();
    }
}

This implementation of forwardToBrowser (from https://stackoverflow.com/a/23268821/3221253) lets the user pick a browser if they have more than one. You could simply open Chrome if you prefer.



回答3:

I resolved it by disabling deep linking in second intent

Manifest

<activity android:name=".Deeplinking">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <data android:host="*.example.com" />
    </intent-filter>
</activity>

And in code I can understand if I want browser/app handle it, and trigger new intent if needed.

private void openInBrowser(String url) {
    setDeepLinkingState(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);

    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));

    setDeepLinkingState(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
}

private void setDeepLinkingState(int state) {
    ComponentName compName = new ComponentName(getPackageName(), getPackageName() + ".Deeplinking");
    getApplicationContext().getPackageManager().setComponentEnabledSetting(
            compName,
            state,
            PackageManager.DONT_KILL_APP);
}


回答4:

This work for me

if(Build.VERSION.SDK_INT < 23) {
    Intent intent = new Intent();
    intent.setAction(android.content.Intent.ACTION_VIEW);
    intent.setDataAndType(i.getData(), i.getType());
    List<ResolveInfo> activities = getPackageManager().queryIntentActivities(intent, 0);
    ArrayList<Intent> targetIntents = new ArrayList<Intent>();
    String thisPackageName = getApplicationContext().getPackageName();
    for (ResolveInfo currentInfo : activities) {
        String packageName = currentInfo.activityInfo.packageName;
        if (!thisPackageName.equals(packageName)) {
            Intent targetIntent = new Intent(android.content.Intent.ACTION_VIEW);
            targetIntent.setDataAndType(intent.getData(), intent.getType());
            targetIntent.setPackage(intent.getPackage());
            targetIntent.setComponent(new ComponentName(packageName, currentInfo.activityInfo.name));
            targetIntents.add(targetIntent);
        }
    }
    if (targetIntents.size() > 0) {
        Intent chooserIntent = Intent.createChooser(targetIntents.remove(0), "Open with");
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[]{}));
        startActivity(chooserIntent);
        finish();
    }
}
// from SDK 23, queryIntentActivities only return your activity, so you need to disable you activity before forward to browser and enable it later.
else {
    final PackageManager pm = getPackageManager();
    final ComponentName component = new ComponentName(this, HandleDeepLinkActivity.class);
    pm.setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
    Intent webIntent = new Intent(Intent.ACTION_VIEW);
    webIntent.setData(i.getData());
    startActivity(webIntent);
    Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            pm.setComponentEnabledSetting(component, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
        }
    }, 500);
}