Android DeepLink原理与应用(2)

上一篇提到Android使用DeepLink跳转有两种方式:Intent跳转、WebView网页跳转。这篇研究一下Android框架如何实现DeepLink。以下Android源代码分析版本为Android7.1。
(1)Intent跳转
这其实是一个Intent filter + start Activity的过程,使用的Intent Catagory是Intent.CATEGORY_BROWSABLE,从这入手。先在Android框架层代码中搜索一下看看哪些地方处理了Intent.CATEGORY_BROWSABLE?发现在处理Intent过滤的工具类中有处理:
frameworks/base/core/java/android/content/IntentFilter.java:

    /**
     * Return if this filter handles HTTP or HTTPS data URIs.
     *
     * @return True if the filter handles ACTION_VIEW/CATEGORY_BROWSABLE,
     * has at least one HTTP or HTTPS data URI pattern defined, and optionally
     * does not define any non-http/https data URI patterns.
     *
     * This will check if if the Intent action is {@link android.content.Intent#ACTION_VIEW} and
     * the Intent category is {@link android.content.Intent#CATEGORY_BROWSABLE} and the Intent
     * data scheme is "http" or "https".
     *
     * @param onlyWebSchemes When true, requires that the intent filter declare
     *     that it handles *only* http: or https: schemes.  This is a requirement for
     *     the intent filter's domain linkage being verifiable.
     * @hide
     */
    public final boolean handlesWebUris(boolean onlyWebSchemes) {
        // Require ACTION_VIEW, CATEGORY_BROWSEABLE, and at least one scheme
        if (!hasAction(Intent.ACTION_VIEW)
            || !hasCategory(Intent.CATEGORY_BROWSABLE)
            || mDataSchemes == null
            || mDataSchemes.size() == 0) {
            return false;
        }

        // Now allow only the schemes "http" and "https"
        final int N = mDataSchemes.size();
        for (int i = 0; i < N; i++) {
            final String scheme = mDataSchemes.get(i);
            final boolean isWebScheme =
                    SCHEME_HTTP.equals(scheme) || SCHEME_HTTPS.equals(scheme);
            if (onlyWebSchemes) {
                // If we're specifically trying to ensure that there are no non-web schemes
                // declared in this filter, then if we ever see a non-http/https scheme then
                // we know it's a failure.
                if (!isWebScheme) {
                    return false;
                }
            } else {
                // If we see any http/https scheme declaration in this case then the
                // filter matches what we're looking for.
                if (isWebScheme) {
                    return true;
                }
            }
        }

        // We get here if:
        //   1) onlyWebSchemes and no non-web schemes were found, i.e success; or
        //   2) !onlyWebSchemes and no http/https schemes were found, i.e. failure.
        return onlyWebSchemes;
    }

看到handlesWebUris()处理Intent.CATEGORY_BROWSABLE。需要注意的是,这个方法会根据传入参数的不同调整判断的标准,如果传入true显然只会识别http/https uri。而从Android DeepLink官方文档上看,uri可以定义成非http/https。另一个方法handleAllWebDataURI()可以满足这个限制:

    /**
     * Return if this filter handle all HTTP or HTTPS data URI or not.  This is the
     * core check for whether a given activity qualifies as a "browser".
     *
     * @return True if the filter handle all HTTP or HTTPS data URI. False otherwise.
     *
     * This will check if:
     *
     * - either the Intent category is {@link android.content.Intent#CATEGORY_APP_BROWSER}
     * - either the Intent action is {@link android.content.Intent#ACTION_VIEW} and
     * the Intent category is {@link android.content.Intent#CATEGORY_BROWSABLE} and the Intent
     * data scheme is "http" or "https" and that there is no specific host defined.
     *
     * @hide
     */
    public final boolean handleAllWebDataURI() {
        return hasCategory(Intent.CATEGORY_APP_BROWSER) ||
                (handlesWebUris(false) && countDataAuthorities() == 0);
    }

继续看handleAllWebDataURI()在什么地方被使用,发现在PackageManagerService的内部类ActivityIntentResolver中,PackageManagerService.ActivityIntentResolver.newResult():

 @Override
        protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
                int match, int userId) {
            if (!sUserManager.exists(userId)) return null;
            if (!mSettings.isEnabledAndMatchLPr(info.activity.info, mFlags, userId)) {
                return null;
            }
            final PackageParser.Activity activity = info.activity;
            PackageSetting ps = (PackageSetting) activity.owner.mExtras;
            if (ps == null) {
                return null;
            }
            ActivityInfo ai = PackageParser.generateActivityInfo(activity, mFlags,
                    ps.readUserState(userId), userId);
            if (ai == null) {
                return null;
            }
            final ResolveInfo res = new ResolveInfo();
            res.activityInfo = ai;
            if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) {
                res.filter = info;
            }
            if (info != null) {
                res.handleAllWebDataURI = info.handleAllWebDataURI();
            }
            res.priority = info.getPriority();
            res.preferredOrder = activity.owner.mPreferredOrder;
            //System.out.println("Result: " + res.activityInfo.className +
            //                   " = " + res.priority);
            res.match = match;
            res.isDefault = info.hasDefault;
            res.labelRes = info.labelRes;
            res.nonLocalizedLabel = info.nonLocalizedLabel;
            if (userNeedsBadging(userId)) {
                res.noResourceId = true;
            } else {
                res.icon = info.icon;
            }
            res.iconResourceId = info.icon;
            res.system = res.activityInfo.applicationInfo.isSystemApp();
            return res;
        }

其中24行使用了PackageParser.ActivityIntentInfo.handleAllWebDataURI(),PackageParser.ActivityIntentInfo是IntentFilter的子类。
继续追一下newResult()这个方法的使用逻辑。
PackageManagerService.ActivityIntentResolver继承自IntentResolver:
frameworks/base/services/core/java/com/android/server/IntentResolver.java
这是一个抽象类,并且属于Android框架内部类,不属于public api。newResult()这个方法在IntentResolver中定义。
在PackageManagerService中并没有对PackageManagerService.ActivityIntentResolver.newResult()的显式使用,所以这应该是一个模板模式,newResult()在基类的主框架流程中被隐式使用,子类只要根据子集的需求override。
在IntentResolver中调用关系:
queryIntent()/queryIntentFromList() -> buildResolveList() -> newResult()
回到PMS,发现一条重要的调用链:
PackageManagerService.queryIntentActivities() ->
PackageManagerService.ActivityIntentResolver.queryIntent() ->
IntentResolver.queryIntent()
作为对外的接口,PackageManager.queryIntentActivities()的作用是根据给定的Intent参数寻找Activity。

在AMS中,有对于这个方法的调用:
ActivityStackSupervisor.realStartActivityLocked() ->
ActivityManagerService.startSetupActivityLocked() ->
PackageManagerService.queryIntentActivities()
查阅相关资料可知(譬如刘超《深入解析Android5.0系统》),ActivityStackSupervisor.realStartActivityLocked()这个方法是start Activity流程中的一环。由此引发上述分析中的对于Intent.CATEGORY_BROWSABLE的处理。

你可能感兴趣的:(Android DeepLink原理与应用(2))