上一篇提到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的处理。

更多相关文章

  1. Unity3D 调用Android原生方法
  2. Android中两种设置全屏的方法 && Android横竖屏切换
  3. Android 保存文件路径方法
  4. Android 下的usb框架及功能点
  5. 阻止一进入页面就弹输入法对话框的方法
  6. Android中SQLiteOpenHelper类的onUpgrade方法的作用
  7. android TabHost(选项卡)的使用方法
  8. Android使用系统方法实现分享到QQ和微信!
  9. Android多种方法获取系统时间

随机推荐

  1. android的动画相关参数说明
  2. android之view获取getWidth()和getHeight
  3. Android 4.1.2系统添加重启功能
  4. ANdroid之蓝牙
  5. Android Toast 长期显示解决方案
  6. AndroidO audio系统之框架简介(一)
  7. Android 事件处理基于Handler 消息处理
  8. Android与MVC设计模式
  9. 〖Android〗Android App项目资源字符串检
  10. android下root权限的获取