美文网首页Android
安卓实现静默安装

安卓实现静默安装

作者: 我是少年520 | 来源:发表于2021-11-27 11:28 被阅读0次
在做医院项目的时候,遇到了医院病人床头屏app需要静默安装的需求。静默安装就是被安装的app在升级或者安装的时候不需要用户手动点击确认安装,让app自动在后台安装或者升级成功。

要想实现app静默安装我们需要下面4个步骤:

1.首先我们需要在配置清单文件里面添加INSTALL_PACKAGE权限
 <uses-permission android:name="android.permission.INSTALL_PACKAGES" />  
2.把该应用的uid设置为系统级别的,在manifest标签下添加以下属性
 android:sharedUserId="android.uid.system"
3.仅仅设置uid,还是没法实现静默安装,因为系统并不认为你这个app是系统级别的应用,所以,还应该对该应用的APK进行系统签名(注意:不是那个静默安装的APK,是这个实现静默安装程序的APK)。签名过程如下:

总共需要三个文件:

  • SignApk.jar %系统源码%/out/host/linux-x86/framework/signapk.jar
  • platform.x509.pem %系统源码%/build/target/product/security/platform.x509.pem
  • platform.pk8 %系统源码%/build/target/product/security/platform.pk8
    由于我们的安卓设备是第三方定制的安卓系统,我们只能去找安卓设备供应商要系统签名需要的这三个文件。
    利用签名工具signapk.jar修改应用程序签名:命令为:
    java -jar signapk.jar platform.x509.pem platform.pk8 my.apk mysigned.apk
    my.apk是我们的应用程序的路径,mysigned.apk是应用系统签名之后生成的新的apk的路径
4.静默安装代码
/**
     * 静默安装
     * 会依次调用Stream-->反射-->Shell
     *
     * @param apkFile APK文件
     * @return 成功或失败
     */
    @SuppressLint("PackageManagerGetSignatures")
    @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
    public static synchronized boolean install(Context context, String apkFile) throws InterruptedException {
        File file;
        if (TextUtils.isEmpty(apkFile) || !(file = new File(apkFile)).exists())
            return false;
        context = context.getApplicationContext();
        //加上apk合法性判断
        AppUtils.AppInfo apkInfo = AppUtils.getApkInfo(file);
        if (apkInfo == null || TextUtils.isEmpty(apkInfo.getPackageName())) {
            LogUtils.iTag(TAG, "apk info is null, the file maybe damaged: " + file.getAbsolutePath());
            return false;
        }

        //加上本地apk版本判断
        AppUtils.AppInfo appInfo = AppUtils.getAppInfo(apkInfo.getPackageName());
        if (appInfo != null) {

            //已安装的版本比apk版本要高, 则不需要安装
            if (appInfo.getVersionCode() >= apkInfo.getVersionCode()) {
                LogUtils.iTag(TAG, "The latest version has been installed locally: " + file.getAbsolutePath(),
                        "app info: packageName: " + appInfo.getPackageName() + "; app name: " + appInfo.getName(),
                        "apk version code: " + apkInfo.getVersionCode(),
                        "app version code: " + appInfo.getVersionCode());
                return true;
            }

            //已安装的版本比apk要低, 则需要进一步校验签名和ShellUID

            PackageManager pm = context.getPackageManager();
            try {
                PackageInfo appPackageInfo, apkPackageInfo;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                    appPackageInfo = pm.getPackageInfo(appInfo.getPackageName(), PackageManager.GET_SIGNING_CERTIFICATES);
                    apkPackageInfo = pm.getPackageArchiveInfo(file.getAbsolutePath(), PackageManager.GET_SIGNING_CERTIFICATES);
                } else {
                    appPackageInfo = pm.getPackageInfo(appInfo.getPackageName(), PackageManager.GET_SIGNATURES);
                    apkPackageInfo = pm.getPackageArchiveInfo(file.getAbsolutePath(), PackageManager.GET_SIGNATURES);
                }

                if (appPackageInfo != null && apkPackageInfo != null &&
                        !compareSharedUserId(appPackageInfo.sharedUserId, apkPackageInfo.sharedUserId)) {
                    LogUtils.wTag(TAG, "Apk sharedUserId is not match",
                            "app shellUid: " + appPackageInfo.sharedUserId,
                            "apk shellUid: " + apkPackageInfo.sharedUserId);
                    return false;
                }

            } catch (Throwable ignored) {

            }


        }
        //        try {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            //由于调用PackageInstaller安装失败的情况下, 重复安装会导致内存占用无限增长的问题.
            //所以在安装之前需要判断当前包名是否有过失败记录, 如果以前有过失败记录, 则不能再使用该方法进行安装
            if (sPreferences == null) {
                sPreferences = context.getSharedPreferences(SP_NAME_PACKAGE_INSTALL_RESULT, Context.MODE_PRIVATE);
            }
            String packageName = apkInfo.getPackageName();
            boolean canInstall = sPreferences.getBoolean(packageName, true);
            if (canInstall) {
                boolean success = installByPackageInstaller(context, file, apkInfo);
                sPreferences.edit().putBoolean(packageName, success).apply();
                if (success) {
                    LogUtils.iTag(TAG, "Install Success[PackageInstaller]: " + file.getAbsolutePath());
                    return true;
                }
            }
        }

        if (installByReflect(context, file)) {
            if (sPreferences != null)
                sPreferences.edit().putBoolean(apkInfo.getPackageName(), true).apply();
            LogUtils.iTag(TAG, "Install Success[Reflect]", file.getPath());
            return true;
        }

        if (installByShell(file, DeviceUtils.isDeviceRooted())) {
            if (sPreferences != null)
                sPreferences.edit().putBoolean(apkInfo.getPackageName(), true).apply();
            LogUtils.iTag(TAG, "Install Success[Shell]", file.getPath());
            return true;
        }
        //        } catch (InterruptedException e) {
        //            throw e;
        //        } catch (Throwable e) {
        //            e.printStackTrace();
        //            LogUtils.wTag(TAG, e);
        //        }
        LogUtils.iTag(TAG, "Install Failure: " + file.getAbsolutePath());
        return false;
    }
附上Demo地址

相关文章

  • 安卓实现静默安装

    在做医院项目的时候,遇到了医院病人床头屏app需要静默安装的需求。静默安装就是被安装的app在升级或者安装的时候不...

  • 安卓静默安装

    好多公司有静默安装的需求(就是不用人去确认就把程序更新了)目前主流的技术有无障碍模式、辅助程序加pm命令模式、系统...

  • 安卓动画样例-放大缩小

    效果图 实现代码 安卓开发入门教程系列汇总 安卓发展历程及前景 安卓发展历程 安卓开发前景展望 初探安卓 安装开...

  • 2018-03-09

    电脑真正实现Windows与安卓 双系统 如何让电脑安装上真正的安卓系统,通常我们Windows系统中安装安...

  • 脏牛漏洞安卓复现

    脏牛漏洞安卓复现 最近花了一些时间研究如何在Android系统上复现脏牛漏洞以及如何利用脏牛漏洞实现应用的静默安装...

  • iOS APP签名原理

    苹果打包应用的时候需要证书才能安装,windows、安卓可以静默安装,苹果的证书机制保证了应用安装的安全性。 证书...

  • 安卓获取root权限的另一个方法之自己实现sudo

    今天为了解决在未root的安卓上实现静默安装,查了一些资料。最后找了一个可行办法,自己编译sudo让后放到系统里,...

  • 安卓静默安装与自启动

    写在前面 静默安装如果在正常的用户手机上除非是残疾用户使用,不然都是耍流氓 本次是因为做一个硬件功能,不带操作的硬...

  • 安卓原生ndk

    安卓安装ndk

  • 安卓开发零基础入门系列

    本文由安卓开发007出品 ## 1.1 安卓发展历程## 1.2 安卓开发前景展望## 1.3 安卓开发入门之安装...

网友评论

    本文标题:安卓实现静默安装

    本文链接:https://www.haomeiwen.com/subject/fqifxrtx.html