365bet开户网-365bet提款审核-365玩球平台

Android下载apk并安装apk(用于软件版本升级用途)

软件版本更新是每个应用必不可少的功能,基本实现方案是请求服务器最新的版本号与本地的版本号对比,有新版本则下载apk并执行安装。请求

Android下载apk并安装apk(用于软件版本升级用途)

软件版本更新是每个应用必不可少的功能,基本实现方案是请求服务器最新的版本号与本地的版本号对比,有新版本则下载apk并执行安装。请求服务器版本号与本地对比很容易,本文就不过多讲解,主要讲解下载apk到安装apk的内容。

一、所需权限

(1)读写外部存储的权限需要动态申请,详见:Android动态获取权限

(2)安装apk的权限从Android8.0开始需要每个应用独立开启

//跳转到开启apk安装权限开启的界面,让用户手动打开

Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,Uri.parse("package:" +getPackageName()));

intentActivityResultLauncher.launch(intent);

二、代码实现

(1)注册provider

在AndroidManifest.xml中声明provider

xmlns:tools="http://schemas.android.com/tools"

package="你的包名">

省略属性。。。>

省略属性。。。>

android:name="androidx.core.content.FileProvider"

android:authorities="你的包名.fileprovider"

android:exported="false"

android:grantUriPermissions="true">

android:name="android.support.FILE_PROVIDER_PATHS"

android:resource="@xml/filepaths" />

在res的xml目录增加filepaths.xml filepaths.xml中配置path路径

path="/"/>

(2)动态申请权限基础BaseActivity

这个类在另外一篇文章中讲解,主要为了方便动态获取权限。

package com.soface.versioncontroll;

import android.content.pm.PackageManager;

import android.os.Build;

import androidx.annotation.NonNull;

import androidx.appcompat.app.AppCompatActivity;

import androidx.core.app.ActivityCompat;

import androidx.core.content.ContextCompat;

import java.util.ArrayList;

import java.util.List;

public class BaseActivity extends AppCompatActivity {

public static final int REQUEST_CONDE =0xFFFF;

/**

* 动态请求权限(入口)

* @param permissionNameList 需要授权的权限名称

*/

public void requestPermission(List permissionNameList){

// TODO: 2023/2/22 第一步:排除(已经获得过授权的权限)=============================================================

List UnauthorizedPermissionNameList = new ArrayList<>();//用于存放未获得授权的权限

for (String permission : permissionNameList){

//检查每个权限是否已经获得授权

int checkResult=ContextCompat.checkSelfPermission(this,permission);

if (checkResult==PackageManager.PERMISSION_GRANTED){

//已获得过授权,直接抛出结果true

throwPermissionResults(permission,true);

}else if (checkResult==PackageManager.PERMISSION_DENIED) {

//未获得授权,把未获得授权的权限加入到thisPermissionNames中,待下一步请求

UnauthorizedPermissionNameList.add(permission);

}else {

//按道理,这里永远不会发生,

//因为checkSelfPermission方法说得很清楚,只会返回PERMISSION_GRANTED或者PERMISSION_DENIED

//但是为了严谨,以防万一,还是给它抛出结果false

throwPermissionResults("Unknown_result",false);

}

}

if (UnauthorizedPermissionNameList.size()==0)return;//表示:全部已经拥有全选,不用往下执行

// TODO: 2023/2/22 第二步:开始申请权限==========================================================================

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

//由于请求权限的参数必须是String[],所以List转到String[]中

String[] UnauthorizedPermissionNames=new String[UnauthorizedPermissionNameList.size()];

for (int k=0;k

UnauthorizedPermissionNames[k]=UnauthorizedPermissionNameList.get(k);

}

//请求权限

ActivityCompat.requestPermissions(this, UnauthorizedPermissionNames, REQUEST_CONDE);

}else {

//低版本的Android不需要动态获取权限,这里直接抛出结果true

throwPermissionResults("Below_VERSION_M",true);

}

}

/**

* 抛出授权结果(出口)

* @param permissionName 权限名称

* @param isSuccess 该权限是否获得授权(true:获得授权 false:未获得授权)

*/

public void throwPermissionResults(String permissionName, boolean isSuccess){

// TODO: 2023/2/22 这里如果isSuccess=false,可以自定义一个弹窗,让用户选择

// 到底是要直接退出应用,还是去设置中开启权限,本文主要是总结动态获取权限,所以弹窗笔者就不写了

}

@Override

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

super.onRequestPermissionsResult(requestCode, permissions, grantResults);

//判断我们的请求码,避免别的事件调用onRequestPermissionsResult,导致我们拿到本不该属于我们的数据

if (requestCode==REQUEST_CONDE){

// 如果请求被取消,则结果数组为空。

if (grantResults.length > 0) {

//循环一个一个地去判断结果

for (int k=0;k

if (grantResults[k] == PackageManager.PERMISSION_GRANTED){

// 权限请求成功,抛出结果true

throwPermissionResults(permissions[k],true);

}

if (grantResults[k] == PackageManager.PERMISSION_DENIED){

// 权限请求失败,抛出结果false

throwPermissionResults(permissions[k],false);

}

}

} else {

//没有任何授权结果,直接抛出结果false

throwPermissionResults("Unknown_result",false);

}

}

}

}

(3)判断需不需要升级最新软件的MainActivity

package com.soface.versioncontroll;

import androidx.activity.result.ActivityResultLauncher;

import androidx.activity.result.contract.ActivityResultContracts;

import androidx.appcompat.app.AppCompatActivity;

import android.Manifest;

import android.content.Intent;

import android.net.Uri;

import android.os.Build;

import android.os.Bundle;

import android.provider.Settings;

import android.util.Log;

import android.view.View;

import android.widget.Button;

import java.util.ArrayList;

import java.util.List;

public class MainActivity extends BaseActivity{

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

//动态请求权限

List perList=new ArrayList<>();

perList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);

perList.add(Manifest.permission.READ_EXTERNAL_STORAGE);

perList.add(Manifest.permission.INTERNET);

requestPermission(perList);

//初始化结果返回接听

initActivityResult();

Button permission=(Button) findViewById(R.id.permission);

permission.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

//当判断需要升级最新软件,则调用这个方法,这里为了方便测试,放在点击事件中

openSetting();

}

});

}

@Override

public void onDestroy() {

super.onDestroy();

stop();

}

@Override

public void throwPermissionResults(String permissionName, boolean isSuccess) {

super.throwPermissionResults(permissionName, isSuccess);

//拿到相应的权限,以及授权结果

switch (permissionName){

case Manifest.permission.WRITE_EXTERNAL_STORAGE:

Log.d("fxHou","WRITE_EXTERNAL_STORAGE授权结果:"+isSuccess);

break;

case Manifest.permission.READ_EXTERNAL_STORAGE:

Log.d("fxHou","READ_EXTERNAL_STORAGE授权结果:"+isSuccess);

break;

default:

break;

}

}

public void openSetting() {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

//Android 8.0以上

if(!getPackageManager().canRequestPackageInstalls()){

//权限没有打开,跳转界面,提示用户去手动打开

Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,Uri.parse("package:" +getPackageName()));

intentActivityResultLauncher.launch(intent);

}else {

//已经拥有权限,直接执行下载apk操作

start();

}

}else {

//开始下载安装

start();

}

}

private ActivityResultLauncher intentActivityResultLauncher;

private void initActivityResult() {

intentActivityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {

if (result.getResultCode() == AppCompatActivity.RESULT_OK) {

//开始下载安装

start();

}

});

}

VersionControl versionControl;

String downloadUrl="http://www.soface.top:8080/source/Public/ApkVersionControl/chart.apk";

String titleStr="麦麦商家版V1.1.2";

String contentStr="正在下载中,请耐心等待";

//开始执行版本更新操作

public void start(){

//初始化版本控制

versionControl=new VersionControl();

versionControl.download(this,downloadUrl,titleStr,contentStr);

versionControl.registerReceiver(this);

}

//停止执行版本更新操作

public void stop(){

//初始化版本控制

versionControl.unRegisterReceiver(MainActivity.this);

versionControl=null;

}

}

(4)下载apk和安装apk的实现类

package com.soface.versioncontroll;

import static android.content.Context.DOWNLOAD_SERVICE;

import android.annotation.SuppressLint;

import android.app.Activity;

import android.app.DownloadManager;

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;

import android.content.IntentFilter;

import android.database.Cursor;

import android.net.Uri;

import android.os.Build;

import android.os.Environment;

import android.provider.Settings;

import android.util.Log;

import androidx.activity.result.ActivityResultLauncher;

import androidx.activity.result.contract.ActivityResultContracts;

import androidx.appcompat.app.AppCompatActivity;

import androidx.core.content.FileProvider;

import java.io.File;

public class VersionControl {

//第一步: 下载APK

private long downloadId=-1;

private DownloadManager downloadManager;

public void download(Context context,String url,String titleStr,String contentStr) {

//创建下载任务

DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));

//在通知栏中显示,默认就是显示的

request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);

request.setTitle(titleStr);

request.setDescription(contentStr);

//设置下载的路径

File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "chart.apk");

request.setDestinationUri(Uri.fromFile(file));

file.getAbsolutePath();

//获取DownloadManager

downloadManager = (DownloadManager)context.getSystemService(DOWNLOAD_SERVICE);

//将下载请求放入队列

downloadId = downloadManager.enqueue(request);

}

//第二步: 监听下载结果

private BroadcastReceiver broadcastReceiver;

public void registerReceiver(Context context) {

// 注册广播监听系统的下载完成事件。

IntentFilter intentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);

broadcastReceiver = new BroadcastReceiver() {

@Override

public void onReceive(Context context, Intent intent) {

long thisDownloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);

if (thisDownloadId!=-1 && downloadId!=-1){

if (thisDownloadId == downloadId) {

//下载完成,检查下载状态

checkStatus(context);

}

}

}

};

context.registerReceiver(broadcastReceiver, intentFilter);

}

public void unRegisterReceiver(Context context){

if (broadcastReceiver!=null) {

context.unregisterReceiver(broadcastReceiver);

}

}

//第三部: 检查下载状态,是否下载成功

@SuppressLint("Range")

private void checkStatus(Context context) {

DownloadManager.Query query = new DownloadManager.Query();

// 执行查询, 返回一个 Cursor (相当于查询数据库)

Cursor cursor = downloadManager.query(query);

if (!cursor.moveToFirst()) {

cursor.close();

}

int id = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_ID));

//通过下载的id查找

query.setFilterById(id);

// 获取下载好的 apk 路径

String localFilename = null;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

localFilename = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));

} else {

localFilename = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));

}

if (cursor.moveToFirst()) {

int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));

switch (status) {

case DownloadManager.STATUS_PAUSED:

//下载暂停

Log.d("fxHou","下载暂停");

break;

case DownloadManager.STATUS_PENDING:

//下载延迟

Log.d("fxHou","下载延迟");

break;

case DownloadManager.STATUS_RUNNING:

//正在下载

Log.d("fxHou","正在下载");

break;

case DownloadManager.STATUS_SUCCESSFUL:

//下载完成安装APK

installApk(context,localFilename);

cursor.close();

break;

case DownloadManager.STATUS_FAILED:

//下载失败

Log.d("fxHou","下载失败");

cursor.close();

break;

default:

break;

}

}

}

//第四部: 安装apk

private void installApk(Context context,String path) {

Intent intent = new Intent(Intent.ACTION_VIEW);

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

File file = new File(Uri.parse(path).getPath());

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

Uri uri = FileProvider.getUriForFile(context, "你的包名.fileprovider", file);

intent.setDataAndType(uri, "application/vnd.android.package-archive");

} else {

intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");

}

context.startActivity(intent);

}

}

← 上一篇: 女管家 (2017) Full online with English subtitle for free – iQIYI
下一篇: 如何买客户数据库 →

相关推荐

冢原卜传
🎮我的世界如何设置重生点全攻略,三法详解
重磅!集群车宝2022“百城千店”加盟帮扶计划发布 2月18日下午,集群车宝“百城千店”2022区域独家赋能加盟帮扶计划正式发布!在集群车宝总部,广东省道路运输协会维修检...
2018俄罗斯世界杯:法国4
有孙悟空角色的手游大全
海尔手机的品质与性能评测(深度剖析海尔手机的特点与优势)
短租房平台哪个好?靠谱短租房平台推荐及避坑指南
几种拓展屏幕/控制的方式(笔记本作为副屏)
手机为什么没有声音了?手机没声音原因以及解决方法介绍
穆罕默德·萨拉赫
庞的解释
2. 渔船一年收入有300万不