React Native Android 下载 apk并安装
实现通过apk链接,下载最新apk并安装功能。
代码如下
DownloadApk
import android.app.Activity;
import android.app.DownloadManager;
import android.app.DownloadManager.Request;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class DownloadApk extends ReactContextBaseJavaModule {
public static String description;
DownloadManager downManager;
Activity myActivity;
final static String log = "DownloadApk";
public DownloadApk(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return "DownloadApk";
}
@ReactMethod
public void downloading(String url, String title, String description) {
DownloadApk.description = description;
myActivity = getCurrentActivity();
downManager = (DownloadManager)myActivity.getSystemService(Context.DOWNLOAD_SERVICE);
Uri uri = Uri.parse(url);
Request request = new Request(uri);
// 设置允许使用的网络类型,这里是移动网络和wifi都可以
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
//设置通知栏标题
request.setNotificationVisibility(Request.VISIBILITY_VISIBLE);
request.setMimeType("application/vnd.android.package-archive");
if (title == null || title.trim().equals("")) {
title = "app 名字"; //这里可以改为自己app的名字
}
request.setTitle(title);
if (description == null || "".equals(description)) {
description = "目标apk正在下载";
}
request.setDescription(description);
request.setAllowedOverRoaming(false);
// 设置文件存放目录
request.setDestinationInExternalFilesDir(myActivity, Environment.DIRECTORY_DOWNLOADS, description);
long downloadId = downManager.enqueue(request);
SharedPreferences sPreferences = myActivity.getSharedPreferences("ggfw_download", 0);
sPreferences.edit().putLong("ggfw_download_apk", downloadId).apply();
}
}
DownloadApkPackage
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
public class DownloadApkPackage implements ReactPackage {
@Nonnull
@Override
public List<NativeModule> createNativeModules(@Nonnull ReactApplicationContext reactContext) {
List modules = new ArrayList();
modules.add(new DownloadApk(reactContext));
return modules;
}
@Nonnull
@Override
public List<ViewManager> createViewManagers(@Nonnull ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
DownloadBroadcastReceiver
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;
import androidx.core.content.FileProvider;
import ***.BuildConfig;//用自己项目的BuildConfig
import java.io.File;
public class DownloadBroadcastReceiver extends BroadcastReceiver {
public DownloadBroadcastReceiver() {
}
public void installApp(Context context) {
File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), DownloadApk.description);
if (file.exists()) {
Intent intent = new Intent(Intent.ACTION_VIEW);
// 由于没有在Activity环境下启动Activity,设置下面的标签
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 24) { //判读版本是否在7.0以上
// 参数1 上下文, 参数2 Provider主机地址 和配置文件中保持一致, 参数3 共享的文件
Uri apkUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + "" + ".fileprovider", file);
// 添加这一句表示对目标应用临时授权该Uri所代表的文件
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
} else {
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
}
context.startActivity(intent);
} else {
Toast.makeText(context, "安装包下载失败", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onReceive(Context context, Intent intent) {
long myDwonloadID = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
SharedPreferences sPreferences = context.getSharedPreferences("ggfw_download", 0);
long refernece = sPreferences.getLong("ggfw_download_apk", 0);
Log.e("DownloadApk", "开始下载");
if (refernece == myDwonloadID) {
DownloadManager dManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Query querybyId = new DownloadManager.Query();
querybyId.setFilterById(myDwonloadID);
Cursor myDownload = dManager.query(querybyId);
String dolownname = null;
Log.e("DownloadApk", String.valueOf(myDownload.moveToFirst()));
if (myDownload.moveToFirst()) {
int status = myDownload.getInt(myDownload.getColumnIndex(DownloadManager.COLUMN_STATUS));
if (status == DownloadManager.STATUS_SUCCESSFUL) {
installApp(context);
} else {
Toast.makeText(context, "下载失败,删除残留文件", Toast.LENGTH_LONG).show();
dManager.remove(myDwonloadID);
myDownload.close();
return;
}
myDownload.close();
}
}
}
}
MainApplication
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
...
new DownloadApkPackage() // add this
);
}
AndroidManifest.xml
<!-- apk下载 -->
<receiver android:name="这里是自己的包路径.DownloadBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
</intent-filter>
</receiver>
<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>
res/xml/file_paths.xml
应该是没有这个文件的,自己新建一个就可以了
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<external-path path="" name="download" />
</paths>
</resources>
ModulesUtil.js
import {
NativeModules
} from 'react-native';
// url apk下载地址,title:下载的名称,url必填,其他选填
const downloadApk = ({url, description, title}) => {
if (!url) {
return null
}
NativeModules.DownloadApk.downloading(url, title, description);
}
export default {
downloadApk,
}