二、详细源码
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、布局文件 srcmainreslayoutactivity_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文件 srcmainresxmlfile_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>
(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、执行的部分在srcmainjavacomtopdoninstallapkdemoMainActivity.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);
}
}
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'
}
1、push 要安装的apk到 /storage/emulated/0/test/serial_port.apk 里面 。
参考文章
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
原文地址:https://blog.csdn.net/qq_37858386/article/details/123075426
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_12793.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!