Android 9.0静默安装与卸载app

最近在开发中有个需求就是要实现静默安装与卸载app的功能,而在PackageManager的api中安装与卸载的接口被隐藏,所以在另辟蹊径,下面把实现的代码分享下

import android.app.PendingIntent;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class InstallApkActivity extends AppCompatActivity implements View.OnClickListener{
    private String TAG ="MainActivity";
    private Button install_btn,uninstall_btn;
    private int mSessionId = -1;
    private PackageInstaller.SessionCallback mSessionCallback;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_install);
        init();
    }
    private void init() {
        install_btn = (Button) findViewById(R.id.btn_install);
        install_btn.setOnClickListener(this);
        uninstall_btn = (Button) findViewById(R.id.btn_uninstall);
        uninstall_btn.setOnClickListener(this);
        mSessionCallback = new InstallSessionCallback();
        getPackageManager().getPackageInstaller().registerSessionCallback(mSessionCallback);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_install:
                installApp("mnt/usb/26A8-0362/MyApp.apk");
                break;
            case R.id.btn_uninstall:
                uninstall("com.xinrui.myapplication");
                break;
        }
    }

    /**
     * 根据包名卸载应用
     *
     * @param packageName
     */
    public void uninstall(String packageName) {
        Intent broadcastIntent = new Intent(this, UnInstallResultReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1,
                broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        PackageInstaller packageInstaller = getPackageManager().getPackageInstaller();
        packageInstaller.uninstall(packageName, pendingIntent.getIntentSender());
    }

   /**
     * 适配android9的安装方法。
     * 全部替换安装
     */
    public void installApp(String apkFilePath) {
        File apkFile = new File(apkFilePath);
        if (!apkFile.exists()) {
            Log.d("MainActivity", "文件不存在");
            return;
        }

        PackageInfo packageInfo = mContext.getPackageManager().getPackageArchiveInfo(apkFilePath, PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES);
        if (packageInfo != null) {
            String packageName = packageInfo.packageName;
            int versionCode = packageInfo.versionCode;
            String versionName = packageInfo.versionName;
            //Log.d("ApkActivity", "packageName=" + packageName + ", versionCode=" + versionCode + ", versionName=" + versionName);
        }

        PackageInstaller packageInstaller = mContext.getPackageManager().getPackageInstaller();
        PackageInstaller.SessionParams sessionParams
                = new PackageInstaller.SessionParams(PackageInstaller
                .SessionParams.MODE_FULL_INSTALL);
        sessionParams.setSize(apkFile.length());

        try {
            mSessionId = packageInstaller.createSession(sessionParams);
        } catch (IOException e) {
            e.printStackTrace();
        }

        //Log.d(TAG, "sessionId---->" + mSessionId);
        if (mSessionId != -1) {
            boolean copySuccess = onTransfesApkFile(apkFilePath);
            //Log.d(TAG, "copySuccess---->" + copySuccess);
            if (copySuccess) {
                execInstallAPP();
            }
        }
    }

    /**
     * 通过文件流传输apk
     *
     * @param apkFilePath
     * @return
     */
    private boolean onTransfesApkFile(String apkFilePath) {
        InputStream in = null;
        OutputStream out = null;
        PackageInstaller.Session session = null;
        boolean success = false;
        try {
            File apkFile = new File(apkFilePath);
            session = mContext.getPackageManager().getPackageInstaller().openSession(mSessionId);
            out = session.openWrite("base.apk", 0, apkFile.length());
            in = new FileInputStream(apkFile);
            int total = 0, c;
            byte[] buffer = new byte[1024 * 1024];
            while ((c = in.read(buffer)) != -1) {
                total += c;
                out.write(buffer, 0, c);
            }
            session.fsync(out);
            //Log.d(TAG, "streamed " + total + " bytes");
            success = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != session) {
                session.close();
            }
            try {
                if (null != out) {
                    out.close();
                }
                if (null != in) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return success;
    }
    /**
     * 执行安装并通知安装结果
     *
     */
    private void execInstallAPP() {
        PackageInstaller.Session session = null;
        try {
            session = mContext.getPackageManager().getPackageInstaller().openSession(mSessionId);
            Intent intent = new Intent(mContext, InstallResultReceiver.class);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext,
                    1, intent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
            session.commit(pendingIntent.getIntentSender());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != session) {
                session.close();
            }
        }
    }

    private class InstallSessionCallback extends PackageInstaller.SessionCallback {
        @Override
        public void onCreated(int sessionId) {
            // empty
        }

        @Override
        public void onBadgingChanged(int sessionId) {
            // empty
        }

        @Override
        public void onActiveChanged(int sessionId, boolean active) {
            // empty
        }

        @Override
        public void onProgressChanged(int sessionId, float progress) {
            if (sessionId == mSessionId) {
                int progres = (int) (Integer.MAX_VALUE * progress);
            }
        }

        @Override
        public void onFinished(int sessionId, boolean success) {
            // empty, finish is handled by InstallResultReceiver
            if (mSessionId == sessionId) {
                if (success) {
                    Log.d("MainActivity", "onFinished() 安装成功");
                } else {
                    Log.d("MainActivity", "onFinished() 安装失败");
                }

            }
        }
    }
}
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
import android.util.Log;

public class InstallResultReceiver extends BroadcastReceiver {
    private static final String TAG = "MainActivity";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d(TAG, "收到安装反馈广播了 action:" + action);
        if (intent != null) { //安装的广播
            final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
                    PackageInstaller.STATUS_FAILURE);
            if (status == PackageInstaller.STATUS_SUCCESS) {
                // success
                Log.d(TAG, "APP Install Success!");
                // InstallAPP.getInstance().sendInstallSucces();
            } else {
                String msg = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
                Log.e(TAG, "Install FAILURE status_massage" + msg);
                //InstallAPP.getInstance().sendFailure(msg);
            }
        }
    }
}
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
import android.util.Log;

public class UnInstallResultReceiver extends BroadcastReceiver {
    private static final String TAG = "MainActivity";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d(TAG, "收到卸载反馈广播了");
        if (intent != null) { //安装的广播
            final int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
                    PackageInstaller.STATUS_FAILURE);
            if (status == PackageInstaller.STATUS_SUCCESS) {
                // success
                Log.d(TAG, "APP UnInstall Success!");
                // InstallAPP.getInstance().sendInstallSucces();
            } else {
                String msg = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
                Log.e(TAG, "UnInstall FAILURE status_massage" + msg);
                //InstallAPP.getInstance().sendFailure(msg);
            }
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.xinrui.headsettest">
    <!--静默安装权限-->
    <uses-permission
        android:name="android.permission.INSTALL_PACKAGES"
        tools:ignore="ProtectedPermissions" />
    <!--应用卸载权限-->
    <uses-permission android:name="permission.REQUEST_INSTALL_PACKAGES" />
    <uses-permission android:name="permission.REQUEST_DELETE_PACKAGES" />
    <uses-permission
        android:name="android.permission.DELETE_PACKAGES"
        tools:ignore="ProtectedPermissions" />

    <!--读写外部存储权限-->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!--允许装载和卸载文件系统权限-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity">
            <!--<intent-filter>-->
                <!--<action android:name="android.intent.action.MAIN" />-->

                <!--<category android:name="android.intent.category.LAUNCHER" />-->
            <!--</intent-filter>-->
        </activity>
        <activity android:name=".AlamActivity">

            <!-- <intent-filter> -->
            <!-- <action android:name="android.intent.action.MAIN" /> -->


            <!-- <category android:name="android.intent.category.LAUNCHER" /> -->
            <!-- </intent-filter> -->
        </activity>
        <activity android:name=".InstallApkActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name=".AlarmBroadCast" />
        <receiver android:name=".AlarmBroadcastReciver" />
        <receiver
            android:name=".InstallResultReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.content.pm.extra.STATUS"/>
            </intent-filter>
        </receiver>
        <receiver
            android:name=".UnInstallResultReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.content.pm.extra.STATUS"/>
            </intent-filter>
        </receiver>
    </application>

</manifest>
  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
Android 9.0 系统中,为了提高设备的安全性,禁止了默认情况下安装未知来源应用程序的权限。然而,我们可以通过编写代码来实现动态请求并获取该权限。 首先,在 AndroidManifest.xml 文件中添加以下权限: ```xml <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/> ``` 然后,在你的应用程序中创建一个方法来请求安装未知来源应用程序的权限: ```java private void requestInstallUnknownAppsPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 判断当前 Android 版本是否高于等于 Android 8.0 if (!getPackageManager().canRequestPackageInstalls()) { // 如果没有权限,跳转到权限设置页面 Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES); intent.setData(Uri.parse("package:" + getPackageName())); startActivityForResult(intent, 1); } } } ``` 在该方法中,我们首先检查设备上的 Android 版本是否高于等于 Android 8.0,然后判断是否已经获得了安装未知来源应用程序的权限。如果没有权限,我们将启动一个意图(Intent)并跳转到权限设置页面,允许用户手动开启该权限。 最后,在你的代码中的适当位置调用该方法: ```java requestInstallUnknownAppsPermission(); ``` 这样一来,每当用户安装你的应用程序时,都会自动检查并请求安装未知来源应用程序的权限,如果没有权限则会跳转到权限设置页面,让用户手动开启。 注意:为了使这些代码生效,你需要确保你的应用程序具有 WRITE_EXTERNAL_STORAGE 权限,这样才能正常安装来自未知来源的应用程序。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安卓兼职framework应用工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值