Android Launcher apk 授信安装

对安装的apk进行校验,除了系统应用市场中下载的,其它渠道的apk都进行安装拦截,并且弹框提示。

首先需要把验证的证书保存在数据库本地,后面需要用到

然后注册系统广播,用于接收 apk 安装时的监听,这个广播由系统发出

新装时的

action 'android.intent.action.PACKAGE_ADDED

替换时的 action

android.intent.action.PACKAGE_REMOVED

android.intent.action.PACKAGE_ADDED

android.intent.action.PACKAGE_REPLACED

删除时的 action

android.intent.action.PACKAGE_REMOVED

android.intent.action.PACKAGE_FULLY_REMOVED

java 复制代码
<receiver android:name\="com.ecarx.verifier.main.VerifyReceiver"
            android:exported\="true"\>
            <intent-filter\>
                <action android:name\="android.intent.action.PACKAGE\_NEEDS\_VERIFICATION" />
                <data android:mimeType\="application/vnd.android.package-archive" />
            </intent-filter\>
</receiver\>

安卓 4.0 新增了 verifyPendingInstall,用于监听包管理,验证时发送广播

验证通过 PackageManager.VERIFICATION_ALLOW 跟验证失败 PackageManager.VERIFICATION_REJECT

在注册一个服务,用于 apk 安装接收到广播后的校验处理

java 复制代码
<service android:name\="com.ecarx.verifier.main.VerifyService"
            android:exported\="true"\>
            <intent-filter\>
                <action android:name\="ecarx.install.verify" />
            </intent-filter\>
</service\>

接下来就是监听跟验证,首先在安装apk时会收到广播,然后可以拿到信息开启服务验证

java 复制代码
public void onReceive(Context context, Intent intent) {
        Log.e(TAG, "onReceive: start");

        String action \= intent.getAction();
        if (Intent.ACTION\_PACKAGE\_NEEDS\_VERIFICATION.equals(action)) {
            Log.e(TAG, "onReceive: " + "ACTION\_PACKAGE\_NEEDS\_VERIFICATION");

            Intent verification \= new Intent();
            verification.setAction(VerifyConstant.VERIFY\_SERVICE\_ACTION);
            verification.setPackage(VerifyConstant.VERIFY\_SERVICE\_PACKAGE\_NAME);

            Bundle sExtras \= new Bundle(intent.getExtras());
            sExtras.putInt(VerifyManager.Cmd.CMD\_KEY, VerifyManager.Cmd.CMD\_VERIFY);
            String path \= intent.getData().getPath();
            Log.e(TAG, "path: " + path);
            if (!path.endsWith(VerifyConstant.INSTALL\_FILE\_SUFFIX)) {
                path \= path + "/base.apk";
            }
            sExtras.putString("PACKAGE\_PATH", path);
            verification.putExtras(sExtras);
            if (Build.VERSION.SDK\_INT >= Build.VERSION\_CODES.O) {
                AppPlugins.appCtx().startForegroundService(verification);
            } else {
                AppPlugins.appCtx().startService(verification);
            }
            return;
        }
        if (Intent.ACTION\_PACKAGE\_VERIFIED.equals(action)) {
            Log.d(TAG, "onReceive: " + "ACTION\_PACKAGE\_VERIFIED");
            return;
        }
    }

服务 VerifyService extends IntentService

系统校验时间默认为10秒超时,如果下载的是大型游戏可能会anr,所以需要默认改下超时时间

并且在服务中需要弹框处理,这两个操作放到 onCreate 中

java 复制代码
@Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");
        Settings.Global.putLong(getContentResolver(), PACKAGE\_VERIFIER\_TIMEOUT, MAX\_VERIFICATION\_TIMEOUT);
        VerifyUtils.setVerifyInstallListener(isAllow \-> {
            Log.d(TAG, "setVerifyInstallListener isAllow : " + isAllow);
            if (!isAllow) {
                ArchTaskExecutor.getInstance().postToMainThread(this::showInstallTipDialog);
            }
        });
    }

然后处理具体的验证逻辑

java 复制代码
@Override
    protected void onHandleIntent(@Nullable Intent intent) {
        if (intent == null) return;
        if (intent.getExtras() == null) return;

        int cmd = intent.getIntExtra(VerifyManager.Cmd.CMD\_KEY, 0);
        switch (cmd) {
            case VerifyManager.Cmd.CMD\_VERIFY: {    
                Bundle extras \= intent.getExtras();
                int id = extras.getInt(PackageManager.EXTRA\_VERIFICATION\_ID);
                String pkgName \= extras.getString(EXTRA\_VERIFICATION\_PACKAGE\_NAME);
                String packagePath \= extras.getString("PACKAGE\_PATH", null);
                String installerPkg \= extras.getString(EXTAR\_VERIFICATION\_INSTALLER\_PKG);

                PackageManager pm \= this.getPackageManager();
                boolean isSystemApp = VerifyUtils.isSystemApp(pkgName);
                Log.e(TAG, "isSystemApp " + isSystemApp);
                if (isSystemApp) {
                    pm.verifyPendingInstall(id, PackageManager.VERIFICATION\_ALLOW);
                    if (DEBUG) {
                        Log.e(TAG, pkgName \+ " : System App ALLOW");
                    }
                    return;
                }

                boolean isOverlayApp = VerifyUtils.isOverlayApp(packagePath);
                Log.e(TAG, "isOverlayApp " + isOverlayApp);
                if (isOverlayApp) {
                    pm.verifyPendingInstall(id, PackageManager.VERIFICATION\_ALLOW);
                    if (DEBUG) {
                        Log.e(TAG, pkgName \+ " : Overlay App ALLOW");
                    }
                    return;
                }

                Log.e(TAG, "installerPkg " + installerPkg);
                if (DEVICESERVICE\_PACKAGE\_NAME.equals(installerPkg) && VerifyUtils.isSystemPackage(DEVICESERVICE\_PACKAGE\_NAME)) {
                    pm.verifyPendingInstall(id, PackageManager.VERIFICATION\_ALLOW);
                    if (DEBUG) {
                        Log.e(TAG, pkgName \+ " : Debugtool install App ALLOW");
                    }
                    return;
                }
                String sha1 \= getMd5VerifyResult(packagePath);

                boolean isLegal = VerifyUtils.isLegal(sha1, pkgName);
                Log.e(TAG, "isLegal " + isLegal);
                if (isLegal) {
                    pm.verifyPendingInstall(id, PackageManager.VERIFICATION\_ALLOW);
                    if (DEBUG) {
                        Log.e(TAG, pkgName \+ " : Legal App ALLOW");
                    }
                    return;
                }
                VerifyUtils.verifyOnlineSign(id, packagePath, pkgName, sha1);
                return;
            }
        }
        }
}        

具体验证方法

java 复制代码
    public static void verifyOnlineResp(int id, String localSha1, String pkgName, SignatureResp signatureResp) {
        String signText \= signatureResp.getSign();
        int signType = signatureResp.getSignType();
        String sha1 \= signatureResp.getApkSign();
        String content \= generateContent(signType, pkgName, sha1);

        boolean verifyResult = VerifyUtils.verifySign(content, signText, publicKeyStr);
        if (verifyResult) {
            SignEntity signEntity \= new SignEntity(pkgName, sha1, content, signType, signText);
            AppDatabase.getInstance().signDao().insertSignSync(signEntity);
        }
        reportVerifyResult(id, pkgName, verifyResult);

    }

    public static void reportVerifyResult(int id, String pkgName, boolean isAllow) {
        int resultCode = isAllow ? PackageManager.VERIFICATION\_ALLOW : PackageManager.VERIFICATION\_REJECT;
        String resultStr \= isAllow ? "Allow" : "Reject";
        AppPlugins.appCtx().getPackageManager().**verifyPendingInstall**(id, resultCode);
        if (listener != null) {
            listener.verifyResult(isAllow);
        }
        Log.e(TAG, pkgName \+ " : " + resultStr);
    }

👀关注公众号:Android老皮!!!欢迎大家来找我探讨交流👀

相关推荐
素师良码13 小时前
第5篇:显示驱动必备调试工具浅析
android
维克兜率天13 小时前
【维克】配对交易的季节性:哪些品种适合长拿?
android·开发语言·笔记·python·算法·kotlin·量化
墨天梦14 小时前
B06_XML控件布局与ViewBinding
android·kotlin
晚风叙码14 小时前
MySQL 表的操作:从建表到删表,一篇讲清楚
android·mysql·oracle
事圆则缓15 小时前
Android 性能优化常见工具与使用场景:从症状到证据的排查指南
android·性能优化
avi911116 小时前
Unity 非后台,非自动构建,但统计报表 BuildReport ,构建自动化系统C#
android·webserver·ios打包·admin·c#后台·unity打包系统·unity自动构建
新鲜势力呀16 小时前
PHP 定时任务系统实战:从 Cron 混乱执行到任务调度中心 + Redis队列 + 失败重试
android·java·redis
YF021117 小时前
Android 16系统 如何修改 eth0 IP ?
android
其实防守也摸鱼17 小时前
渗透测试学习计划(全栈综合 · 零基础进阶)
android·数据库·学习·安全·oracle·自动化·学习方法
释厄62317 小时前
BSD 简单真理循环论——简单真理 × 复杂循环=大一统
android·开发语言·kotlin