2022-02-22 AndroidN之后 app代码安装apk,以及提示“There was a problem parsing the package“的解决方案

一、在AndroidR 的机器上运行,看demo代码的架构

 二、详细源码

    1、在清单文件AndroidManifest.xml 添加权限和provider。如果是androidR或者更高版本还得加<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />,不然安装的过程会提示"There was a problem parsing the package"解析错误。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.topdon.installapkdemo">

    <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/Theme.InstallApkDemo">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.topdon.installapkdemo.fileProvider"
            android:grantUriPermissions="true"
            android:exported="false">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

    </application>


    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
</manifest>

    2、布局文件 src\main\res\layout\activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <Button
        android:id="@+id/confirm"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_alignParentBottom ="true"
        android:background="#00BCD4"
        android:textSize="35dp"
        android:text="confirm" />
</androidx.constraintlayout.widget.ConstraintLayout>

    3、在xml包下创建一个xml文件 src\main\res\xml\file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
    <paths>
        <external-path
            name="external"
            path="." />
        <external-files-path
            name="external_files"
            path="." />
        <cache-path
            name="cache"
            path="." />
        <external-cache-path
            name="external_cache"
            path="." />
        <files-path
            name="files"
            path="." />
    </paths>

    4、file_paths文件简单解析

(1)files-path:
对应物理路径:getFilesDir(
对应具体路径:/data/user/0/包名/files
(2)cache-path:
对应物理路径:getCacheDir()
对应具体路径:/data/user/0/包名/cache
(3)external-path:
对应物理路径:Environment.getExternalStorageDirectory()
对应具体路径:/storage/emulated/0
(4)external-files-path:
对应物理路径:getExternalFilesDir("名字")
对应具体路径:/storage/emulated/0/Android/data/包名/files/名字
(5)external-cache-path:
对应物理路径:getExternalCacheDir()
对应具体路径:/storage/emulated/0/Android/data/包名/cache

    5、执行的部分在src\main\java\com\topdon\installapkdemo\MainActivity.java

package com.topdon.installapkdemo;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import androidx.fragment.app.FragmentActivity;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class MainActivity extends AppCompatActivity implements  View.OnClickListener{
    private String TAG = "MainActivity";
    private static String mUrl;
    private static Context mContext;
    private   Button  btnConfirm;
    private static final int REQUEST_CODE = 1024;

    public Boolean checkPermission() {
        boolean isGranted = true;
        if (android.os.Build.VERSION.SDK_INT >= 23) {
            if (this.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                isGranted = false;
            }
            if (this.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) !=PackageManager.PERMISSION_GRANTED) {
                isGranted = false;
            }
            Log.i("读写权限获取"," : "+isGranted);
            if (!isGranted) {
                this.requestPermissions(
                        new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission
                                .ACCESS_FINE_LOCATION,
                                Manifest.permission.READ_EXTERNAL_STORAGE,
                                Manifest.permission.WRITE_EXTERNAL_STORAGE},
                        102);
            }
        }
        return isGranted;
    }

    /** 检查Android 11或更高版本的文件权限 */
    private void  checkAndroid11FilePermission() {
        // Android 11 (Api 30)或更高版本的写文件权限需要特殊申请,需要动态申请管理所有文件的权限
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            if (Environment.isExternalStorageManager()) {
               // Log.i("ABCD","此手机是Android 11或更高的版本,且已获得访问所有文件权限")
                Toast.makeText(this, "Android VERSION  R OR ABOVE,HAVE MANAGE_EXTERNAL_STORAGE GRANTED!", Toast.LENGTH_LONG).show();
                // TODO requestOtherPermissions() 申请其他的权限
            } else {
                Toast.makeText(this, "Android VERSION  R OR ABOVE,NO MANAGE_EXTERNAL_STORAGE GRANTED!", Toast.LENGTH_LONG).show();
               // showDialog(activity, """本应用需要获取"访问所有文件"权限,请给予此权限,否则无法使用本应用""") {
                   // launcher.launch(Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION))
                }
        } else {
            Log.i("ABCD","此手机版本小于Android 11,版本为:API ${Build.VERSION.SDK_INT},不需要申请文件管理权限");
            // TODO requestOtherPermissions() 申请其他的权限
        }
    }

    private void requestmanageexternalstorage_Permission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            // 先判断有没有权限
            if (Environment.isExternalStorageManager()) {
                Toast.makeText(this, "Android VERSION  R OR ABOVE,HAVE MANAGE_EXTERNAL_STORAGE GRANTED!", Toast.LENGTH_LONG).show();
            } else {
                Toast.makeText(this, "Android VERSION  R OR ABOVE,NO MANAGE_EXTERNAL_STORAGE GRANTED!", Toast.LENGTH_LONG).show();
                Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
                intent.setData(Uri.parse("package:" + this.getPackageName()));
                startActivityForResult(intent, REQUEST_CODE);
            }
        }
    }

    private void installAPK(Context context,File apkFile) {
        Intent intent = new Intent();
        if (context == null) {
            return;
        }
        if (!apkFile.exists()) {
            Toast.makeText(this, "the apk is not exists", Toast.LENGTH_LONG).show();
            return;
        }
        String authority = getApplicationContext().getPackageName() + ".fileProvider";
        String packageName = context.getPackageName();
        Uri uri;
        if (apkFile != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                //uri = FileProvider.getUriForFile(context, packageName
                        //+ ".fileprovider", apkFile);
                //uri = FileProvider.getUriForFile(context, authority, apkFile);
                uri = FileProvider.getUriForFile(context, "com.topdon.installapkdemo.fileProvider", apkFile);
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                intent.setAction(Intent.ACTION_INSTALL_PACKAGE);
            } else {
                uri = Uri.fromFile(apkFile);
                intent.setAction(Intent.ACTION_VIEW);
            }
            intent.setDataAndType(uri, "application/vnd.android.package-archive");
            startActivity(intent);
        }
    }

    @Override
    public void onClick(View v) {

        if (v.getId()==R.id.confirm) {
            //String pathApk = "/data/data/com.topdon.installapkdemo/files/serial_port.apk";
            //installAPK(this,new File(pathApk));

            String pathApk ="file:///storage/emulated/0/test/serial_port.apk";
            installAPK(this,new File(Uri.parse(pathApk).getPath()));

            //String pathApk = "/sdcard/serial_port.apk";
            //installAPK(this,new File(pathApk));
        }
        //Toast.makeText(this, "onClick", Toast.LENGTH_LONG).show();
        }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        checkPermission();
        requestmanageexternalstorage_Permission();
        btnConfirm = (Button) findViewById(R.id.confirm);
        btnConfirm.setOnClickListener(this);
    }
}

  6、build.gradle

plugins {
    id 'com.android.application'
}

android {
    compileSdkVersion 31
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.topdon.installapkdemo"
        minSdkVersion 25
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

三、编译成apk,然后安装,运行测试

1、push 要安装的apk到 /storage/emulated/0/test/serial_port.apk 里面 。

2、点击安装按钮

 

 

参考文章

android 使用FileProvider 兼容apk 在7.0版本无法安装_svenWang_的专栏-CSDN博客

安卓开发之apk自动安装代码_太阳在发光!-CSDN博客_安卓自动安装apk

android上边用代码安装apk文件_yangzm的专栏-CSDN博客_android 代码安装apk

https://www.jb51.net/article/189012.htm

https://www.jb51.net/article/235575.htm

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值