多源影视搜索
应用内升级主要分为两部分:下载和安装,以下按照这两部分开始讲述,文章最后会附上全代码。 文中部分xxx需要替换成对应的包名或apk名称1. 权限配置 AndroidManifest.xml权限请求<uses-permission android:name=”android.permission.REQUEST_INSTALL_PACKAGES” />
<uses-permission android:name=”android.permission.ACCESS_DOWNLOAD_MANAGER” />provider配置,针对6.0以上系统<application
….
<provider
android:name=”androidx.core.content.FileProvider”
android:authorities=”包名.fileprovider”
android:exported=”false”
android:grantUriPermissions=”true”>
<meta-data
android:name=”android.support.FILE_PROVIDER_PATHS”
android:resource=”@xml/file_paths” />
</provider>
….
</application>res/xml 新建一个 file_paths.xml 文件(如果没有就创建文件夹再创建文件)1. 具体 external-path 和 external-files-path 用法我也不是很懂[捂脸],建议直接google用法。2. 我下载时的路径是 getExternalFilesDir 设置的路径,按下面的方式写没有问题。<?xml version=”1.0″ encoding=”utf-8″?>
<resources>
<paths>
<external-path name=”external_files_path” path=”Android/data”/>
</paths>
</resources>2. 下载Apk
配置没问题后,开始正式写代码,检查版本更新调用接口就不写了,按自己需求写,只挑重点讲述。
步骤检查版本更新对比版本号/**
* 版本号比较
*
* @param version1 服务器版本号
* @param version2 当前版本号
* @return 0代表相等,1代表version1大于version2,-1代表version1小于version2
*/
private int compareVersion(String version1, String version2) {
if (version1.equals(version2)) {
return 0;
}
String[] version1Array = version1.split(“\\.”);
String[] version2Array = version2.split(“\\.”);
int index = 0;
// 获取最小长度值
int minLen = Math.min(version1Array.length, version2Array.length);
int diff = 0;
// 循环判断每位的大小
while (index < minLen
&& (diff = Integer.parseInt(version1Array[index])
– Integer.parseInt(version2Array[index])) == 0) {
index++;
}
if (diff == 0) {
// 如果位数不一致,比较多余位数
for (int i = index; i < version1Array.length; i++) {
if (Integer.parseInt(version1Array[i]) > 0) {
return 1;
}
}
for (int i = index; i < version2Array.length; i++) {
if (Integer.parseInt(version2Array[i]) > 0) {
return -1;
}
}
return 0;
} else {
return diff > 0 ? 1 : -1;
}
}3. 展示版本更新提示
4. 检查权限是否开启(安装未知来源应用)
//版本判断
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//获取是否有安装未知来源应用的权限
haveInstallPermission = mContext.getPackageManager().canRequestPackageInstalls();
}
if (!haveInstallPermission) {
Toast.makeText(mContext, “请打开安装未知来源应用的权限”, Toast.LENGTH_SHORT).show();
Uri packageURI = Uri.parse(“package:” + mContext.getPackageName());
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI);
mContext.startActivityForResult(intent, requestCode);
}
// 在Activity中接收下载完成的回调
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// 请求完安装权限后的回调
if (requestCode == WBVersionUpdateManager.WBVersionUpdateManagerPermissionCode && getPackageManager().canRequestPackageInstalls()) {
versionUpdateManager.downloadAPK(versionUpdateManager.updateVersion, versionUpdateManager.downloadURL);
}
}5. 在activity中注册和取消注册广播 否则收不到下载完成通知
// 注册广播
downloadManagerReceiver = new DownloadManagerReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
context.registerReceiver(downloadManagerReceiver, intentFilter);
//解除注册
context.unregisterReceiver(downloadManagerReceiver);
/**
* 广播接收器
*/
public class DownloadManagerReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// 下载完成
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
//获取 downloadmanager 下载任务id
long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
//安装应用
mListener.downloadCompleted();
}
}
}6. 通知和权限问题写好后,开始正式下载Apk,使用原生的DownloadManager
public void downloadAPK(String updateVersion, String downloadURL) {
Toast.makeText(mContext, “正在下载….”, Toast.LENGTH_LONG).show();
downloadManager = (DownloadManager)mContext.getSystemService(DOWNLOAD_SERVICE);
//已存在 — 删除
File apkFile = new File(mContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), “xxx.apk”);
if (apkFile != null && apkFile.exists()) {
apkFile.delete();
}
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downloadURL));
// 完成后显示通知栏
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
//设置存储路径 –这个是应用专用的,软件卸载后,下载的文件将随着卸载全部被删除
request.setDestinationInExternalFilesDir(mContext, Environment.DIRECTORY_DOWNLOADS, “xxx.apk”);
//设置 文件类型
request.setMimeType(“application/vnd.android.package-archive”);
downloadManager.enqueue(request);
}3. 安装Apk下载完成后,可以直接执行安装操作了
步骤找到下载的路径Uri,需要适配6.0和以上版本,因为获取Uri的方式变了。安装,通过 activity.startActivity(intent) 直接完成安装。private Uri getUri() {
Uri uri;
File file_save = new File(mContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString()+”/xxx.apk”);
if (Build.VERSION.SDK_INT >= 24) {
// 适配android7.0 ,不能直接访问原路径
// 需要对intent 授权
uri = FileProvider.getUriForFile(mContext,
mContext.getPackageName() + “.fileprovider”,
file_save);
} else {
uri = Uri.fromFile(file_save);
}
return uri;
}
public void install(Activity activity) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(getUri(), “application/vnd.android.package-archive”);
activity.startActivity(intent);
}4. 错误解析在做需求时碰到了两种错误,下面一一对应讲解:
“解析包异常”大概率是路径问题,这里分两种情况解决:
1. 首先试试 6.0 版本是否有问题,如果有问题,说明是下载和安装时的路径填写不对,可以打印出来看看。
2. 试试 6.0 以上版本是否有问题,这种情况出问题的较多,原因可能是:
1. AndroidManifest.xml 中写的 fileprovider 不对
2. files_path.xml 文件写的不对
3. 下载的路径不对(如果6.0系统都没问题,这个应该也没问题)
4. 获取Uri的时候不对
以上问题最有效的方式还是分别把下载的路径和Uri打印出来,一目了然。
“安装错误”恭喜!看到这个提示证明之前所有步骤都没问题,只是打包方式不同罢了,比如手机上安装的是AS运行的包,服务器上是打的 release 包。
打一个低版本的release包安装在手机上,打一个高版本的放服务器上即可
5. WBVersionUpdateManager源码
只需在 Activity 里调用一个 checkUpdateVersion() 方法即可。在 Activity 的 onResume() 和 onPause() 里分别调用 注册广播 和 解除广播 的方法在 Activity 的 onActivityResult 里做 “安装未知来源”权限的操作 (本操作暂时只能通过跳转方式,不能通过动态请求方式,并且返回后,应再次判断一下权限是否打开,再进行下一步操作)// 安装未知来源权限判断
getPackageManager().canRequestPackageInstalls()源码:WBVersionUpdateManager.java/****************************************************
*
* @class: WBVersionUpdateManager
* @desc: 版本更新管理类
* @date: 2/26/21 10:20 AM
*
* @author: wenbin
*
****************************************************/
/**
* 版本更新管理类
* 用法:
* 1. 初始化 WBVersionUpdateManager
* 2. 在activity的 onResume() 中调用 registerDownloadBroadcast注册广播
* 3. 在activity的 onPause() 中调用 unregisterDownloadBroadcast解除注册广播
* 4. 在初始化回调接口中处理 没有权限 和 下载完成 的处理
*(1) 没有权限: 跳转系统应用设置页面
*(2) 下载完成: 调用 install()方法安装apk, 如果没有注册广播收不到监听
*/
public class WBVersionUpdateManager {
/*没有权限请求时的requestCode*/
public static int WBVersionUpdateManagerPermissionCode = 010;
/*传入的context*/
private Context mContext;
/*监听listener*/
private WBVersionUpdateManager.versionUpdateListener mListener;
/*最新的版本号*/
public String updateVersion;
/*下载链接*/
public String downloadURL;
/*是否有安装apk的权限*/
private Boolean haveInstallPermission = true;
/*下载apk的manager*/
private DownloadManager downloadManager;
/*下载完成的接收器*/
private DownloadManagerReceiver downloadManagerReceiver;
/**
* 初始化
* @param context context
* @param listener listener
*/
public WBVersionUpdateManager(Context context, WBVersionUpdateManager.versionUpdateListener listener) {
this.mContext = context;
this.mListener = listener;
}
/**
* 检查版本更新
*/
public void checkUpdateVersion() {
// 等于1意味着服务器版本号大于当前版本号, 需要弹出提示更新
// 如果弹出过当前最新版本的提示, 则不再弹出
if (compareVersion(updateVersion, versionName) == 1) {
//版本判断
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//获取是否有安装未知来源应用的权限
haveInstallPermission = mContext.getPackageManager().canRequestPackageInstalls();
}
showUpdateTipdialog(updateVersion, summary, downloadURL);
} else {
mListener.alreadyLastVersion();
}
}
/**
* 版本号比较
*
* @param version1 服务器版本号
* @param version2 当前版本号
* @return 0代表相等,1代表version1大于version2,-1代表version1小于version2
*/
private int compareVersion(String version1, String version2) {
if (version1.equals(version2)) {
return 0;
}
String[] version1Array = version1.split(“\\.”);
String[] version2Array = version2.split(“\\.”);
int index = 0;
// 获取最小长度值
int minLen = Math.min(version1Array.length, version2Array.length);
int diff = 0;
// 循环判断每位的大小
while (index < minLen
&& (diff = Integer.parseInt(version1Array[index])
– Integer.parseInt(version2Array[index])) == 0) {
index++;
}
if (diff == 0) {
// 如果位数不一致,比较多余位数
for (int i = index; i < version1Array.length; i++) {
if (Integer.parseInt(version1Array[i]) > 0) {
return 1;
}
}
for (int i = index; i < version2Array.length; i++) {
if (Integer.parseInt(version2Array[i]) > 0) {
return -1;
}
}
return 0;
} else {
return diff > 0 ? 1 : -1;
}
}
/**
* 展示版本更新提示
* @param serverVersion 服务器版本号
* @param updateSummary 更新内容
* @param downloadURL 下载url
*/
private void showUpdateTipdialog(String serverVersion, String updateSummary, String downloadURL) {
int mCurrentDialogStyle = com.qmuiteam.qmui.R.style.QMUI_Dialog;
new QMUIDialog.MessageDialogBuilder(mContext)
.setTitle(“检查到有新版本”)
.setMessage(serverVersion + “\n” + updateSummary)
.setCanceledOnTouchOutside(false)
.setSkinManager(QMUISkinManager.defaultInstance(mContext))
.addAction(“取消”, new QMUIDialogAction.ActionListener() {
@Override
public void onClick(QMUIDialog dialog, int index) {
mListener.clickCancel();
dialog.dismiss();
}
})
.addAction(0, “立即更新”, QMUIDialogAction.ACTION_PROP_POSITIVE, new QMUIDialogAction.ActionListener() {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onClick(QMUIDialog dialog, int index) {
dialog.dismiss();
XLog.d(“点击立即更新”);
if (!haveInstallPermission) {
Toast.makeText(mContext, “请打开安装未知来源应用的权限”, Toast.LENGTH_SHORT).show();
Uri packageURI = Uri.parse(“package:” + mContext.getPackageName());
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI);
mListener.haveNoInstallPermission(intent, WBVersionUpdateManagerPermissionCode);
}else {
//下载更新
downloadAPK(serverVersion, downloadURL);
}
}
})
.create(mCurrentDialogStyle).show();
}
/**
* 下载apk并安装
* @param updateVersion 最新版本
* @param downloadURL 下载url
*/
public void downloadAPK(String updateVersion, String downloadURL) {
if (updateVersion == null || downloadURL == null) {
return;
}
Toast.makeText(mContext, “正在下载….”, Toast.LENGTH_LONG).show();
downloadManager = (DownloadManager)mContext.getSystemService(DOWNLOAD_SERVICE);
//已存在 — 删除
File apkFile = new File(mContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), “xxx.apk”);
if (apkFile != null && apkFile.exists()) {
apkFile.delete();
}
//下载 (AppCont.Update_URL 是你的app下载地址)
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downloadURL));
// 完成后显示通知栏
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
//设置存储路径 –这个是应用专用的,软件卸载后,下载的文件将随着卸载全部被删除
request.setDestinationInExternalFilesDir(mContext, Environment.DIRECTORY_DOWNLOADS, “xxx.apk”);
//设置 文件类型
request.setMimeType(“application/vnd.android.package-archive”);
downloadManager.enqueue(request);
}
/**
* 安装apk
*/
public void install(Activity activity) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(getUri(), “application/vnd.android.package-archive”);
activity.startActivity(intent);
}
/**
* 获取下载的apk的Uri地址
* @return Uri地址
*/
private Uri getUri() {
Uri uri;
File file_save = new File(mContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString()+”/xxx.apk”);
if (Build.VERSION.SDK_INT >= 24) {
// 适配android7.0 ,不能直接访问原路径
// 需要对intent 授权
uri = FileProvider.getUriForFile(mContext,
mContext.getPackageName() + “.fileprovider”,
file_save);
} else {
uri = Uri.fromFile(file_save);
}
XLog.d(uri);
return uri;
}
/**
* 注册广播
* @param context context
*/
public void registerDownloadBroadcast(Context context) {
//注册广播
downloadManagerReceiver = new DownloadManagerReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
context.registerReceiver(downloadManagerReceiver, intentFilter);
}
/**
* 取消注册广播
* @param context context
*/
public void unregisterDownloadBroadcast(Context context) {
//解除注册
context.unregisterReceiver(downloadManagerReceiver);
}
/**
* 广播接收器
*/
public class DownloadManagerReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
//下载完成
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
//获取 downloadmanager 下载任务id
long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
//安装应用
mListener.downloadCompleted();
}
}
}
/**
* manager的回调接口
*/
public interface versionUpdateListener {
/**
* 没有安装权限
*/
void haveNoInstallPermission(Intent intent, int requestCode);
/**
* 下载完成
*/
void downloadCompleted();
/**
* 已经是最新版本
*/
void alreadyLastVersion();
/**
* 点击取消
*/
void clickCancel();
}
}源码:Activiy里的用法@Override
protected void onCreate(Bundle savedInstanceState) {
/*初始化检查更新manager*/
versionUpdateManager = new WBVersionUpdateManager(MainActivity.this, new WBVersionUpdateManager.versionUpdateListener() {
@Override
public void haveNoInstallPermission(Intent intent, int requestCode) {
MainActivity.this.startActivityForResult(intent, requestCode);
}
@Override
public void downloadCompleted() {
versionUpdateManager.install(MainActivity.this);
}
@Override
public void alreadyLastVersion() {
XLog.d(“已是最新版本”);
}
@Override
public void clickCancel() {
XLog.d(“点击取消”);
}
});
/*检查更新*/
versionUpdateManager.checkUpdateVersion();
}
@Override
protected void onResume() {
super.onResume();
// 注册下载更新的广播
versionUpdateManager.registerDownloadBroadcast(MainActivity.this);
}
@Override
protected void onPause() {
super.onPause();
//解除注册
versionUpdateManager.unregisterDownloadBroadcast(MainActivity.this);
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// 请求完安装权限后的回调
if (requestCode == WBVersionUpdateManager.WBVersionUpdateManagerPermissionCode && getPackageManager().canRequestPackageInstalls()) {
versionUpdateManager.downloadAPK(versionUpdateManager.updateVersion, versionUpdateManager.downloadURL);
}
}
易优cms博客模板