如何在Activity中获取调用者 -- getReferrer()

如何在Activity中获取调用者 – getReferrer()

前言

为什么要在Activity中获取调用者?
主要是安全定制两个方面的需求吧。

  • 安全需求:
    一般Activity如果已经对外开放了(即exported为true,或者加了Intent-filter),那么对Activity的保护就会降低,形成Activity攻击面,引入了风险。如果只对某几个app开放其Activity,则可以获取调用者的信息,并进行控制。

  • 定制需求:
    如果被启动的Activity想对特定的调用者进行定制操作,则需要知道调用者是谁。


在Activity中获取调用者的方法

注:先列出所有可能的方法,后面会给出哪些方法可行。

  • Binder.getCallingUid()Binder.getCallingPid(),然后根据uid,pid查找到包名

  • Activity的 getCallingPackage()getCallingActivity()

  • Activity的 getReferrer()【注意:Android 5.1(Api level 22)中才引入的】

  • 反射的方式获取Activity的 mReferrer: reflectGetReferrer()【注:自定义函数,目的是获取到 android.app.Activity类的 mReferrer的值,也需要Api level 22(含)之后才能使用】

这里先给出结论:

  • 方法1:不能在调用者startActivity()的时候获取到调用者的包名,只能用于Activity用到的Binder同步调用的地方。

  • 方法2: 在特定情况下可以使用getCallingPackage()getCallingActivity(),即如果Activity是通过startActivityForResult启动的,则可以使用。

  • 方法3: Activity的getReferrer()是不可靠的,因为调用者可以自己设置referrer的值。

  • 方法4:是对方法3的改进,消除getReferrer()可能返回的不可靠的值,直接获取可靠的mReferrer值(目前来看是可靠的)。


关于mReferrer的细节

Activity的getReferrer()

需要注意的是,此方法是在Android 5.1 (Api level 22)中引入的,Android 5.1之前是不能使用的。

Intent.java

public static final String EXTRA_REFERRER
            = "android.intent.extra.REFERRER";
    public static final String EXTRA_REFERRER_NAME
            = "android.intent.extra.REFERRER_NAME";

Activity.java

public Uri getReferrer() {
        Intent intent = getIntent();
        // 优先从Intent的Intent.EXTRA_REFERRER数据获取Uri,作为referrer
        Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
        if (referrer != null) {
            return referrer;
        }
        // 如果之前没有获取到,则从intent的Intent.EXTRA_REFERRER_NAME数据获取,并转换成Uri
        String referrerName = intent.getStringExtra(Intent.EXTRA_REFERRER_NAME);
        if (referrerName != null) {
            return Uri.parse(referrerName);
        }
        // 如果上面都没有获取到,则将mReferrer转换成android-app://的形式
        if (mReferrer != null) {
            return new Uri.Builder().scheme("android-app").authority(mReferrer).build();
        }
        return null;// 都没获取到的话,返回null
    }
反射的方式获取Activity的mReferrer

需要注意的是,此方法是基于getReferrer()(mReferrer)的,所以也必须在Android 5.1 (Api level 22)及 5.1 之后才能用。

自定义方法:

private String reflectGetReferrer() {
        try {
            Class activityClass = Class.forName("android.app.Activity");

            Field refererField = activityClass.getDeclaredField("mReferrer");
            refererField.setAccessible(true);
            String referrer = (String) refererField.get(MainActivity.this);
            return referrer;
        } catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException e) {
            e.printStackTrace();
            return "No referrer";
        }
    }

总结

  • 通过反射的方式reflectGetReferrer()获取到的mReferrer,是调用者的包名,目前来看是可靠的,但是需要在Android5.1(Api level 22)以及之后才能用。

  • getCallingPackage()getCallingActivity()只有在startActivityForResult()的时候才可以得到调用者的包名。

  • Activity的getReferrer()是不可靠的,因为调用者可以自己设置referrer的值。所以不能依赖此值来判断调用者。

  • Binder.getCallingUid()Binder.getCallingPid()一般用在同步调用中,在这几个情况中并不适用。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值