Android下载APK并安装(支持8.0和5.0,6.0和7.0没有测试不知道)

老大让弄APK直接代码更新,之前没有写过不会,网上溜达了一圈,也抄了一圈,把代码贴出来,下次用的时候可以直接COPY,也希望能帮到没写过的朋友。

流程:

1.  请求后端,判断是否需要更新当前APK。

2.  判断android版本号是否>5.0(Build.VERSION.SDK_INT是否>=23)来决定是否申请读写权限。

3.  android版本6.0以上需要用到共享文件(Provider)。

4.  判断android版本是否为8.0来决定是否申请安装APK的权限(8.0的APK安装都要申请)。

5.  下载APK。

6.  安装APK。

1.  这里第一步就不写了,直接请求后端判断即可。

2.  根据android版本申请读写权限(读写权限的onRequestPermissionResult我基本不写,不放心的话可以自己加一下):

// 6.0 以上申请SD卡读写权限
public static void myPermission() {
     if (Build.VERSION.SDK_INT >= 23) {
        String[] permissions = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};
        ActivityCompat.requestPermissions(content, permissions, PERMISSION_WR);
    }
}

3.  android版本为6.0以上的需要到AndroidManifest申请安装路径,在Application节点下:

<application
    ...
 >

    <!--适配android 7.0以及以上更新APK路径-->
    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.baiding.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>
</application>

3.0. name是固定写法,但不唯一,想知道的可以自己去搜。
3.1. authorities="你的包名.FileProvider。
3.2. exproted指能否被其他应用程序、组件调用或交互,这里false就行,也可以视自己情况而定(大神的解释:https://blog.csdn.net/id19870510/article/details/8141803)。
3.3. grantUriPermission看字面字面意思就是授予读取Uri的权限,一定要设为true,不然你7.0甚至以上的就直接GG了。
3.4. meta-data里的直接copy,跟3.0一样。
3.5. resource先写上="@xml/file_paths",然后在res下建一个名为xml的Directory,再在xml下建一个名为file_paths的Android resource file(看下图)。
3.6. 在file_paths中写下路径名和路径:
<resources xmlns:android="http://schemas.android.com/apk/res/android">

    <external-path
        name="."
        path="baiding" />

    name是一个引用字符串,path是文件夹的相对路径,apk存在哪个文件夹下全看path里写的啥,不记得哪里
    看到的,有人说name可以空,但是我实时是报错了,然后又看到博客说 . 代表接受所有字符串,果断填了个 .
     1. <files-path name="name" path="path" />
    物理路径相当于Context.getFilesDir() + /path/。
     2.<cache-path name="name" path="path" />
    物理路径相当于Context.getCacheDir() + /path/。
     3. <external-path name="name" path="path" />
    物理路径相当于Environment.getExternalStorageDirectory() + /path/。
     4. <external-files-path name="name" path="path" />
    物理路径相当于**Context.getExternalFilesDir(String) **+ /path/。
     5. <external-cache-path name="name" path="path" />
    物理路径相当于Context.getExternalCacheDir() + /path/

</resources>

4. 根据android版本是否>=8.0来决定是否申请安装APK的权限:

//8.0安装新版本APK权限
private void peimissionO() {
    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O) {
        boolean b = context.getPackageManager().canRequestPackageInstalls(); //检测是否允许安装apk
        if (b) {
            //安装apk
        } else {
            //请求安装权限
            String[] permission = {Manifest.permission.REQUEST_INSTALL_PACKAGES};
            ActivityCompat.requestPermissions((Activity) context, permission, PERMISSION_UP_APK);
        }
    }
}

//权限
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode){
        case PERMISSION_UP_APK:
            if (grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){
                //安装APK
            }else {
                //跳转到安装未知应用界面
                Intent intent=new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
                startActivityForResult(intent,PERMISSION_GET_SETTTING);//on line 380
            }
            break;
    }
}

5.下载APK(这里没有做进度条):

//开始下载APK
public void downloadApk() {
    Thread downLoadThread = new Thread(mdownApkRunnable2);
    downLoadThread.start();
}

private Runnable mdownApkRunnable2 = new Runnable() {
    @Override
    public void run() {
        try {
            URL url = new URL(urlAPK);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                apkFile = new File(Environment.getExternalStorageDirectory().getPath()+"/baiding");
                // 网上说在file_path里用files-path的话,对应的java里就得用getFilesDir(),本人吃了大亏,
                // 8.0是正常了,但是天杀的5.0居然每次都找不到这个文件,安装的时候直接提示安装包不存在,果断
                // 把file_paths里的files换成了external,不知道是我的原因还是咋回事,别问我啥情况,我不知道
                //apkFile = new File("data/data/com.baiding/files/baiding/");//5.0no,8.0ok
                //apkFile = new File(context.getFilesDir().getPath()+"/baiding");//5.0no,8.0ok
                if (!apkFile.exists()) {
                    apkFile.mkdirs();
                }
                file = new File(apkFile+"/baiding.apk");
                if (!file.exists()) {
                    file.createNewFile();
                }
            FileOutputStream fos = new FileOutputStream(file);
            InputStream is = connection.getInputStream();
            byte[] buf = new byte[1024 * 5];
            int len;
            while ((len = is.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }
            is.close();
            fos.close();
            handler.sendEmptyMessage(12);//下载完毕,通知安装
        } catch (MalformedURLException e) {
        } catch (IOException e) {
            //有人跟我说打这个e特别消耗内存
        }
    }
};

6. 安装APK:

// 更换新的APK(android版本低于8.0)
public void installAPK() {
    //跳转安装
    Intent intent = new Intent(Intent.ACTION_VIEW);
    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O) {//  8.0
        peimissionO();//检查安装权限
    } else {
        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N) {//  7.0
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            //第二个参数是你的包名+.FileProvider(你也可以直接去AndroidMenifest中把你刚才写的provider的authorities拷贝过来,Fileprovider开头大小写不限)
            Uri contentUri = FileProvider.getUriForFile(context, "com.baiding.Fileprovider", file);
            intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
        } else {//7.0以下
            intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");

            //下面这俩,反正我的是不奏效
            //intent.setDataAndType(Uri.pars("file:"+"data/data/com.baiding/files/baiding/"),
            // "application/vnd.android.package-archive");
            //intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
        }
        context.startActivity(intent);
    }
}

END...

注: 1.自己看博客的时候没看明白,导致自己APK明明已经下载成功,但是怎么都解析失败,其实就错在xml的file_path里的 path,比如你用的是external-path,在创建文件的时候就一定要把path加进去(第一次做,血的教训):

File file= new File(Environment.getExternalStorageDirectory().getPath()+"/path里的那几个字母");

          2.如果你xml的file_path用的是files-path,完事你走到安装apk这一步了,老是提示什么文件夹不存在,程序包不存在啥啥啥的,趁时间还早,试试external-path或者其他的吧,本人愣是在files-path耗了N个小时后受不了才换的,瞬间啥病都没了,唉。

猜你喜欢

转载自blog.csdn.net/qq_41873558/article/details/81709365