在系统层实现三方应用去除广告页

在系统层实现三方应用去除广告页

这个功能只是我的一个小练习(如何去除的思路来自千里马feamework的教程,自己在发散思维后进行实现的),在实际开发中可以借鉴去解决一些其他的问题,但是关于三方应用去除开屏广告这个操作会有其他各式各样的影响因素

思路:
将应用的包名、广告页的类名、主界面的类名都dump出来然后写死到Array.xml里面,在framework/base/core下的Activity.java的startActivity方法里面去实现
大致流程:这里新写一个方法,将数据从xml文件取出(使用TypedArray暂存)并处理后存入ConcurrentHashMap(线程安全)「当前只存了包名和主界面类名,后面还需要使用广告页类名去判断是否弹广告」,当拿到系统资源且传入的intent不为空时,开始遍历packageName并判断传入的intent的包名是否存在于map中,若存在,返回主界面包名类名,若不存在,返回空
在startActivity中,判断intent和上面的方法都不为空的时候,使用intent.setComponent方法修改ComponentName。
之后startActivity带着修改后的intent继续运行。

在xml中写入数据

这里我是在framework/base/core/res/res/values/arrays.xml中新增数据

    <string-array name="package_name">
        <item>com.android.contacts/com.android.contacts.activities.PeopleActivity/com.android.contacts.activities.ContactEditorActivity</item>
        <item>com.android.settings/com.android.settings.Settings/com.android.phone.MobileNetworkSettings</item>
        <item>a1/b/c</item>
        <item>a2/b/c</item>
        <item>a3/b/c</item>
        <item>a4/b/c</item>
        <item>a5/b/c</item>
        <item>a6/b/c</item>
        <item>a7/b/c</item>
        <item>a8/b/c</item>
        <item>a9/b/c</item>
        <item>a10/b/c</item>
        <item>a11/b/c</item>
        <item>a12/b/c</item>
        <item>a13/b/c</item>
        <item>a14/b/c</item>
        <item>a15/b/c</item>
        <item>a16/b/c</item>

    </string-array>

注:记得在symbols.xml里面定义一下

在framework/base/core下的Activity.java中新增如下方法

这里主要是去获取xml文件中存储的内容并且判断传入的intent的包名是否是xml文件中所拥有的,如果有,则输出我们需要的包名类名,如果没有则为null

/**
     * 获取包名类名数据并进行分组
     */
    private String removeInfomercial(Intent intent){
        //存储包名以及修改后的类名
        ConcurrentHashMap<String, String> packageName = new ConcurrentHashMap<String,String>();
        //获取系统资源是否存在
        int resId = Resources.getSystem().getIdentifier("package_name","array","android");
        //log确认是否获取到资源
        Log.i("test3", String.valueOf(resId));
        if (resId != 0){
            //将arrays.xml中package_name中的包名类名数据存入typedArray中
            TypedArray overalls = Resources.getSystem().obtainTypedArray(resId);
            //遍历typedArray并拆分拿到的字符串后存入map中
            for (int i = 0;i<overalls.length();i++){
                String[] packageNames = overalls.getString(i).split("/");
                packageName.put(packageNames[0],packageNames[2]);
            }
            //回收 TypedArray 避免内存泄漏
            overalls.recycle();
            //log确认内容填充完毕
            Log.i("test3",packageName.toString());
        }else {
            //处理未找到资源情况
            Log.i("test3","未获取数据");
        }
        //当拿到系统资源且传入的intent不为空时,开始遍历packageName并判断传入的intent的包名是否存在于map中
        if (intent != null && resId != 0){
            for (String name:packageName.keySet()){
                Log.i("test3","map中的key值"+name);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.DONUT) {
                    Log.i("test3","map中的key值与拿到的包名对比结果"+name.equals(intent.getComponent().getPackageName())+"key值"+name+"包名"+intent.getComponent().getPackageName().toString());
                    //注意:获取包名时:通过intent.getComponent().getPackageName()而不是intent.getPackage()
                    //前者是一个标准且有效的方式来获取显式 Intent 中目标组件的包名,而后者则不是一个标准方法,可能不存在
                    if (name.equals(intent.getComponent().getPackageName())){
                        //若存在则返回对应的包名类名
                        Log.i("test3","输出的包名为"+packageName.get(name));
                        return packageName.get(name);
                    }
                }
            }
        }

        Log.i("test3","intent输出内容"+intent.getComponent().getPackageName().toString());

        //若不存在则返回null
        return null;

    }

这里是具体实现的地方,这块也比较简单,自己看

@Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        //判空后修改需要打开的界面
        if (removeInfomercial(intent) != null && intent.getComponent() != null){
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.DONUT) {
                //创建新的ComponentName并填充传入的数据
                ComponentName destCom = new ComponentName(intent.getComponent().getPackageName(),removeInfomercial(intent));


                //其他界面缺少android.intent.category.LAUNCHER和android.intent.category.LAUNCHER导致无法启动
                //或者在AndroidManifest.xml文件中的exported属性被设置为false。当exported属性为false时,表示该Activity只能被本应用调用

//                Log.i("test3","修改后的内容:"+removeInfomercial(intent));
                //修改打开的界面
                intent.setComponent(destCom);
                // 设置Intent的动作为MAIN
                intent.setAction(Intent.ACTION_MAIN);
                // 添加LAUNCHER类别
                intent.addCategory(Intent.CATEGORY_LAUNCHER);
                Log.i("test3","传入的数据"+destCom.toString());
//                Log.i("test3","修改内容"+intent.setComponent(destCom).toString());
            }
        }else {
            Log.i("test3","未进行修改");
        }
        //获取打开界面的action
        Log.i("test3","   action为: "+intent.toString());
	}

遇到的问题:

  • 如何获取数据
    • 在symbols.xml内没有去声明导致拿不到数据
    • 仿照Activity .java里面使用TypedArray拿到数据后再遍历然后去处理
  • 在removeInfomercial类中进行map中的数据与应用传到系统层的数据进行判断时出现空指针
    • 获取包名时:通过intent.getComponent().getPackageName()而不是intent.getPackage()
    • 前者是一个标准且有效的方式来获取显式 Intent 中目标组件的包名,而后者则不是一个标准方法,可能不存在
  • 由于是在模拟器上进行测试,选择的应用目标界面缺少android.intent.action.MAIN和android.intent.category.LAUNCHER两个参数导致无法启动
    • 强行添加Action和Category后还是有问题
    • 当前来看是因为exported属性为false时,表示该Activity只能被本应用调用
log打印的intent内容示例

02-07 16:58:11.819  2275  2275 I test3   :    action为: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.settings/.Settings (has extras) }
02-07 16:58:17.737  2902  2902 I test3   :    action为: Intent { act=android.intent.action.MAIN cmp=com.android.phone/.MobileNetworkSettings }

02-07 16:55:39.557  2275  2275 I test3   :    action为: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.contacts/.activities.PeopleActivity bnds=[96,634][192,730] (has extras) }
02-07 16:55:41.066  2413  2413 I test3   :    action为: Intent { act=android.intent.action.INSERT dat=content://com.android.contacts/contacts pkg=com.android.contacts (has extras) }

逻辑存在的缺陷

  • 只要有应用调用startActivity就会走一遍这个逻辑,代码中存在两个遍历,在数据量大的情况下会导致各种性能问题
  • 应用的开屏广告过程中部分应用会进行一些资源的加载,在资源没有加载完就进入主界面可能会导致闪屏甚至如果是关键资源未加载可能会导致应用crash
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值