Android8.0安装第三方应用的问题总结

  • 1、AndroidManifest中添加权限
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

android.permission.REQUEST_INSTALL_PACKAGES 这个不是危险权限,不需要动态申请

android.permission.WRITE_EXTERNAL_STORAGE,android.permission.READ_EXTERNAL_STORAGE,这两个需要动态申请权限

  • 2、AndroidManifest中添加provider
<provider android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileProvider"
    android:grantUriPermissions="true"
    android:exported="false">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

android:authorities是用来标识provider的唯一标识,在同一部手机上一个”authority”串只能被一个app使用,冲突的话会导致app无法安装。我们可以利用manifest placeholders来保证authority的唯一性。

android:exported必须设置成false,否则运行时会报错java.lang.SecurityException: Provider must not be exported。

android:grantUriPermissions用来控制共享文件的访问权限,也可以在java代码中设置。

  • 3.在工程里添加file_paths.xml

在项目的res目录下创建xml目录,再创建file_paths.xml文件 内容如下:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <paths> <files-path path="Android/data/${applicationId}/" name="files_root" />

        <files-path path="." name="files_path" />

        <root-path path="." name="root"/>

        <external-path path="." name="files"/></paths>
</paths>

  • 4.在代码里申请安装未知来源应用的权限
boolean isGranted = getPackageManager().canRequestPackageInstalls();

如果haveInstallPermission 为 true,则说明你的应用有安装未知来源应用的权限,你直接执行安装应用的操作即可。

如果haveInstallPermission 为 false,则说明你的应用没有安装未知来源应用的权限,则无法安装应用。由于这个权限不是运行时权限,所以无法再代码中请求权限,还是需要用户跳转到设置界面中自己去打开权限。

Uri packageURI = Uri.parse("package:"+mActivity.getPackageName());
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,packageURI);
mActivity.startActivityForResult(intent,REQUEST_CODE_UNKNOWN_APP_SOURCES);
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case REQUEST_CODE_INSTALL_APP:
            Log.i(TAG, "onActivityResult: " + (mIsInstallSuccess?"安装成功" : "安装失败"));

            break;
        case REQUEST_CODE_UNKNOWN_APP_SOURCES://位置apk资源权限
            Log.i(TAG, "onActivityResult: REQUEST_CODE_UNKNOWN_APP_SOURCES" );
            if (resultCode == ACTIVITY_RESULT_OK) {
                install();
            }
            break;
    }
}

在onActivityResult中去接收结果,如果同意继续执行安装方法

 Uri apkUri = FileProvider.getUriForFile(mActivity, BuildConfig.APPLICATION_ID + ".fileProvider", new File(apkpath));
 Intent install = new Intent(Intent.ACTION_VIEW);
 //添加这一句表示对目标应用临时授权该Uri所代表的文件
//install.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
install.setDataAndType(apkUri, "application/vnd.android.package-archive");
mActivity.startActivityForResult(install,REQUEST_CODE_INSTALL_APP);

上源码:

package com.picovr.install;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.util.Log;

import androidx.annotation.RequiresApi;
import androidx.core.content.FileProvider;

import java.io.File;

/**
 * @author Admin
 * @version $
 * @des 安装器安装
 * @updateAuthor dawn$
 * @updateDes 安装器安装
 */
public class ApkInstall
{
    private static final String TAG = "ApkInstall";
    public static final int REQUEST_CODE_INSTALL_APP = 2;
    public static final int REQUEST_CODE_UNKNOWN_APP_SOURCES = 1;
    public static final int ACTIVITY_RESULT_OK = -1;
    private MainActivity mActivity;
    private String mApkPath;
    private boolean mIsInstallSuccess = false;

    public interface MainActivityResultCallback {
        void onActivityResult(int requestCode, int resultCode, Intent data);
        void onInstallUninstallBroadcastReceiver(Context context, Intent intent);
    }
    public ApkInstall(Context context, String appPath) {
        mActivity = (MainActivity) context;
        mActivity.setInstallCallback(mInstallCallback);
        mApkPath = appPath;
        install();
    }



    public void install() {
        File file = new File(mApkPath);
        if (file.exists()) {
            installBySystem(mApkPath);
        }
    }
    private MainActivityResultCallback mInstallCallback = new MainActivityResultCallback() {
        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            switch (requestCode) {
                case REQUEST_CODE_INSTALL_APP:
                    Log.i(TAG, "onActivityResult: " + (mIsInstallSuccess?"安装成功" : "安装失败"));

                    break;
                case REQUEST_CODE_UNKNOWN_APP_SOURCES://位置apk资源权限
                    Log.i(TAG, "onActivityResult: REQUEST_CODE_UNKNOWN_APP_SOURCES" );
                    if (resultCode == ACTIVITY_RESULT_OK) {
                        install();
                    }
                    break;
            }
        }

        @Override
        public void onInstallUninstallBroadcastReceiver(Context context, Intent intent) {
            String packages = intent.getDataString().split(":")[1];
            String action = intent.getAction();
            if (Intent.ACTION_PACKAGE_ADDED.equals(action) || Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
                Log.d(TAG, packages + "应用程序安装了");
                mIsInstallSuccess = true;
            } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
                Log.d(TAG, packages + "应用程序卸载了");
            }
        }
    };


    private void installBySystem( String apkPath) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        File file = new File(apkPath);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        Log.d(TAG, String.format("onActivityResult installBySystem:", apkPath));
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            installApksO(apkPath);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            installApksN(apkPath);
        }else {
            installCommon(apkPath);
        }
    }

    /**
     * android7以下
     */
    private void installCommon(String path){
        Intent install = new Intent(Intent.ACTION_VIEW);
        install.setDataAndType(Uri.parse("file://" + path), "application/vnd.android.package-archive");
        mActivity.startActivityForResult(install,REQUEST_CODE_INSTALL_APP);
    }

    /**
     * android7
     * @param path
     */
    private void installApksN( String path) {
        Uri apkUri = FileProvider.getUriForFile(mActivity, "com.pvr.agent.fileprovider", new File(path));
        Intent install = new Intent(Intent.ACTION_VIEW);
        install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        install.setDataAndType(apkUri, "application/vnd.android.package-archive");
        mActivity.startActivityForResult(install,REQUEST_CODE_INSTALL_APP);
    }

    /**
     * android8.x
     * @param path
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    private void installApksO( final String path){
        String apkpath = path;

        boolean isGranted = mActivity.getPackageManager().canRequestPackageInstalls();
        if (isGranted) {
            Uri apkUri = FileProvider.getUriForFile(mActivity, BuildConfig.APPLICATION_ID + ".fileProvider", new File(apkpath));
            Intent install = new Intent(Intent.ACTION_VIEW);
            //添加这一句表示对目标应用临时授权该Uri所代表的文件
//            install.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            install.setDataAndType(apkUri, "application/vnd.android.package-archive");
            mActivity.startActivityForResult(install,REQUEST_CODE_INSTALL_APP);
        } else {
            Log.i(TAG, "installMethodThree: 安装应用需要打开未知来源权限,请去设置中开启权限" + path);
            Uri packageURI = Uri.parse("package:"+mActivity.getPackageName());
            Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,packageURI);
            mActivity.startActivityForResult(intent,REQUEST_CODE_UNKNOWN_APP_SOURCES);
        }
    }
}

 

参考连接:https://www.jianshu.com/p/6b7bd2a59096

还看了很多相似链接有点记不清了,这里就不一一列举了

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Hosshot2020

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

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

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

打赏作者

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

抵扣说明:

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

余额充值