Intent.parseUri()详解

Intent.parseUri()详解

由于经常会有类似下面的控制启动界面代码:

this.startActivity(Uri.parse(url));
this.startActivity(Intent.parseUri(url));

注意两者区别
第一种写法只能使用类似 http(s)/file等 协议开头的url,
而第二种写法除了以上协议外,还可以启动Activity界面

至于如何启动Activity,则是我们本篇分析的主要内容

实际上 我们分析源代码可知

源代码如下:

/**
 * Create an intent from a URI.  This URI may encode the action,
 * category, and other intent fields, if it was returned by
 * {@link #toUri}.  If the Intent was not generate by toUri(), its data
 * will be the entire URI and its action will be ACTION_VIEW.
 *
 * <p>The URI given here must not be relative -- that is, it must include
 * the scheme and full path.
 *
 * @param uri The URI to turn into an Intent.
 * @param flags Additional processing flags.
 *
 * @return Intent The newly created Intent object.
 *
 * @throws URISyntaxException Throws URISyntaxError if the basic URI syntax
 * it bad (as parsed by the Uri class) or the Intent data within the
 * URI is invalid.
 *
 * @see #toUri
 */
public static Intent parseUri(String uri, @UriFlags int flags) throws URISyntaxException {
    int i = 0;
    try {
        final boolean androidApp = uri.startsWith("android-app:");
        // Validate intent scheme if requested.
        if ((flags&(URI_INTENT_SCHEME|URI_ANDROID_APP_SCHEME)) != 0) {
            if (!uri.startsWith("intent:") && !androidApp) {
                Intent intent = new Intent(ACTION_VIEW);
                try {
                    intent.setData(Uri.parse(uri));
                } catch (IllegalArgumentException e) {
                    throw new URISyntaxException(uri, e.getMessage());
                }
                return intent;
            }
        }
        i = uri.lastIndexOf("#");
        // simple case
        if (i == -1) {
            if (!androidApp) {
                return new Intent(ACTION_VIEW, Uri.parse(uri));
            }
        // old format Intent URI
        } else if (!uri.startsWith("#Intent;", i)) {
            if (!androidApp) {
                return getIntentOld(uri, flags);
            } else {
                i = -1;
            }
        }
        // new format
        Intent intent = new Intent(ACTION_VIEW);
        Intent baseIntent = intent;
        boolean explicitAction = false;
        boolean inSelector = false;
        // fetch data part, if present
        String scheme = null;
        String data;
        if (i >= 0) {
            data = uri.substring(0, i);
            i += 8; // length of "#Intent;"
        } else {
            data = uri;
        }
        // loop over contents of Intent, all name=value;
        while (i >= 0 && !uri.startsWith("end", i)) {
            int eq = uri.indexOf('=', i);
            if (eq < 0) eq = i-1;
            int semi = uri.indexOf(';', i);
            String value = eq < semi ? Uri.decode(uri.substring(eq + 1, semi)) : "";
            // action
            if (uri.startsWith("action=", i)) {
                intent.setAction(value);
                if (!inSelector) {
                    explicitAction = true;
                }
            }
            // categories
            else if (uri.startsWith("category=", i)) {
                intent.addCategory(value);
            }
            // type
            else if (uri.startsWith("type=", i)) {
                intent.mType = value;
            }
            // launch flags
            else if (uri.startsWith("launchFlags=", i)) {
                intent.mFlags = Integer.decode(value).intValue();
                if ((flags& URI_ALLOW_UNSAFE) == 0) {
                    intent.mFlags &= ~IMMUTABLE_FLAGS;
                }
            }
            // package
            else if (uri.startsWith("package=", i)) {
                intent.mPackage = value;
            }
            // component
            else if (uri.startsWith("component=", i)) {
                intent.mComponent = ComponentName.unflattenFromString(value);
            }
            // scheme
            else if (uri.startsWith("scheme=", i)) {
                if (inSelector) {
                    intent.mData = Uri.parse(value + ":");
                } else {
                    scheme = value;
                }
            }
            // source bounds
            else if (uri.startsWith("sourceBounds=", i)) {
                intent.mSourceBounds = Rect.unflattenFromString(value);
            }
            // selector
            else if (semi == (i+3) && uri.startsWith("SEL", i)) {
                intent = new Intent();
                inSelector = true;
            }
            // extra
            else {
                String key = Uri.decode(uri.substring(i + 2, eq));
                // create Bundle if it doesn't already exist
                if (intent.mExtras == null) intent.mExtras = new Bundle();
                Bundle b = intent.mExtras;
                // add EXTRA
                if      (uri.startsWith("S.", i)) b.putString(key, value);
                else if (uri.startsWith("B.", i)) b.putBoolean(key, Boolean.parseBoolean(value));
                else if (uri.startsWith("b.", i)) b.putByte(key, Byte.parseByte(value));
                else if (uri.startsWith("c.", i)) b.putChar(key, value.charAt(0));
                else if (uri.startsWith("d.", i)) b.putDouble(key, Double.parseDouble(value));
                else if (uri.startsWith("f.", i)) b.putFloat(key, Float.parseFloat(value));
                else if (uri.startsWith("i.", i)) b.putInt(key, Integer.parseInt(value));
                else if (uri.startsWith("l.", i)) b.putLong(key, Long.parseLong(value));
                else if (uri.startsWith("s.", i)) b.putShort(key, Short.parseShort(value));
                else throw new URISyntaxException(uri, "unknown EXTRA type", i);
            }
            // move to the next item
            i = semi + 1;
        }
        if (inSelector) {
            // The Intent had a selector; fix it up.
            if (baseIntent.mPackage == null) {
                baseIntent.setSelector(intent);
            }
            intent = baseIntent;
        }
        if (data != null) {
            if (data.startsWith("intent:")) {
                data = data.substring(7);
                if (scheme != null) {
                    data = scheme + ':' + data;
                }
            } else if (data.startsWith("android-app:")) {
                if (data.charAt(12) == '/' && data.charAt(13) == '/') {
                    // Correctly formed android-app, first part is package name.
                    int end = data.indexOf('/', 14);
                    if (end < 0) {
                        // All we have is a package name.
                        intent.mPackage = data.substring(14);
                        if (!explicitAction) {
                            intent.setAction(ACTION_MAIN);
                        }
                        data = "";
                    } else {
                        // Target the Intent at the given package name always.
                        String authority = null;
                        intent.mPackage = data.substring(14, end);
                        int newEnd;
                        if ((end+1) < data.length()) {
                            if ((newEnd=data.indexOf('/', end+1)) >= 0) {
                                // Found a scheme, remember it.
                                scheme = data.substring(end+1, newEnd);
                                end = newEnd;
                                if (end < data.length() && (newEnd=data.indexOf('/', end+1)) >= 0) {
                                    // Found a authority, remember it.
                                    authority = data.substring(end+1, newEnd);
                                    end = newEnd;
                                }
                            } else {
                                // All we have is a scheme.
                                scheme = data.substring(end+1);
                            }
                        }
                        if (scheme == null) {
                            // If there was no scheme, then this just targets the package.
                            if (!explicitAction) {
                                intent.setAction(ACTION_MAIN);
                            }
                            data = "";
                        } else if (authority == null) {
                            data = scheme + ":";
                        } else {
                            data = scheme + "://" + authority + data.substring(end);
                        }
                    }
                } else {
                    data = "";
                }
            }
            if (data.length() > 0) {
                try {
                    intent.mData = Uri.parse(data);
                } catch (IllegalArgumentException e) {
                    throw new URISyntaxException(uri, e.getMessage());
                }
            }
        }
        return intent;
    } catch (IndexOutOfBoundsException e) {
        throw new URISyntaxException(uri, "illegal Intent URI format", i);
    }
}

详细请看上面的注解

类似的可构造Uri如下:

intent:#Intent;component=com.android.calendar/com.android.calendar.LaunchActivity;end

参考

  1. Intent.java源代码
  2. 小米手机MIUI远程代码执行漏洞分析
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值