String apkPath = "/storage/usbhost1/apk";//本地APK的根目录,不同的屏路径不同
我这里是将要更新的apk文件放在U盘里apk这个文件夹下(不同的屏,路径不同)
/** * 获取APK文件的名字 * * @param usbPath APK在U盘里的根目录 */ private String getApkName(String usbPath) { ArrayListdatas = new ArrayList<>(); File file = new File(usbPath); if (file.exists()) {//判断是否有指定文件夹 // 得到该路径文件夹下所有的文件 File[] files = file.listFiles(); // 将所有的文件存入ArrayList中,并过滤所有apk格式的文件 if (files != null) { for (File file1 : files) { //判断是否是要更新的apk文件 1.是否是apk文件 2.更新apk前半部分名称是否相同 (UpdateApk) if (checkIsApkFile(file1.getPath()) && file1.getName().substring(0, 9).equals("UpdateApk")) { datas.add(file1.getName());//添加到本地数组中 Log.i(TAG, "ssss::: " + file1.getName()); } } } if (datas.size() < 1) { Log.e(TAG, "getApkName: 文件夹里为null"); return null; } else { Log.d(TAG, "getApkName: ---有这个安装包:" + datas.get(datas.size() - 1)); return datas.get(datas.size() - 1);//返回当前数组中最后一个APK文件名 } } else { Toast.makeText(MainActivity.this, "没有知道当前文件夹~", Toast.LENGTH_SHORT).show(); return null; } }
/**
* 检查扩展名,判断是否是.apk文件
*
* @param fName 文件名
* @return
*/
@SuppressLint("DefaultLocale")
private boolean checkIsApkFile(String fName) {
boolean isApkFile = false;
// 获取扩展名
String FileEnd = fName.substring(fName.lastIndexOf(".") + 1,
fName.length()).toLowerCase();
if (FileEnd.equals("apk")) {
isApkFile = true;
} else {
isApkFile = false;
}
return isApkFile;
}
这里主要是获取apk的版本信息 version
/**
* 获APK包的信息:版本号,名称,图标 等..
*
* @param usbPath APK包的绝对路径
*/
private void apkInfo(String usbPath) {
Log.i(TAG, "apkInfo: ----");
PackageManager pm = getPackageManager();
PackageInfo pkgInfo = pm.getPackageArchiveInfo(usbPath, PackageManager.GET_ACTIVITIES);
if (pkgInfo != null) {
ApplicationInfo appInfo = pkgInfo.applicationInfo;
/* 必须加这两句,不然下面icon获取是default icon而不是应用包的icon */
appInfo.sourceDir = usbPath;
appInfo.publicSourceDir = usbPath;
// 得到应用名
String appName = pm.getApplicationLabel(appInfo).toString();
this.appName = appName;
// 得到包名
String packageName = appInfo.packageName;
// 得到版本信息
String version = pkgInfo.versionName;
this.version = version;
/* icon1和icon2其实是一样的 */
Drawable icon1 = pm.getApplicationIcon(appInfo);// 得到图标信息
Drawable icon2 = appInfo.loadIcon(pm);
drawable1 = icon1;
drawable2 = icon2;
String pkgInfoStr = String.format("PackageName:%s, Vesion: %s, AppName: %s", packageName, version, appName);
Log.i(TAG, String.format("PkgInfo: %s", pkgInfoStr));
} else {
Log.e(TAG, "apkInfo: null");
}
}
/**
* 获取版本号
*
* @return
* @throws Exception
*/
public String getVersionName() throws Exception {
// 获取packagemanager的实例
PackageManager packageManager = getPackageManager();
// getPackageName()是你当前类的包名,0代表是获取版本信息
PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(), 0);
return packInfo.versionName;
}
/**
* 提取String中的数字
*
* @param s 字符串
* @return
*/
private String getNumber(String s) {
String regEx = "[^0-9]";
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(s);
return m.replaceAll("").trim();
}
/**
* 判断是否需要更新APK
*
* @param apkPath apk绝对路径
* @throws Exception
*/
private void updataApk(String apkPath) throws Exception {
if (appName.equals(getResources().getString(R.string.app_name))) {
//比较版本号的大小~
if (Integer.valueOf(getNumber(version)) > Integer.valueOf(getNumber(getVersionName()))) {
installApk(apkPath);
} else {
Log.e(TAG, "updataApk: ---APK文件的版本是过低");
Toast.makeText(MainActivity.this, "这个已经是最新版本了", Toast.LENGTH_SHORT).show();
}
} else {
Log.e(TAG, "updataApk: ---这个APK文件不能用于本地更新");
Toast.makeText(MainActivity.this, "没有可更新的软件", Toast.LENGTH_SHORT).show();
}
}
/**
* 安装APK
*
* @param apkPath U盘APK文件绝对路径
*/
private void installApk(String apkPath) throws Exception {
//关闭定时器
if (disposable != null && !disposable.isDisposed()) {
disposable.dispose();
}
StringBuffer sb = new StringBuffer();
sb.append("当前版本:");
sb.append(getVersionName());
sb.append("\n要更新的版本:");
sb.append(version);
sb.append("\n是否更新?");
Dialog dialog = new AlertDialog.Builder(MainActivity.this)
.setTitle("软件更新")
.setMessage(sb.toString())
// 设置内容
.setPositiveButton("更新", // 设置确定按钮
(dialog1, which) -> {
//apk文件的本地路径
File apkfile = new File(apkPath);
//会根据用户的数据类型打开android系统相应的Activity。
Intent intent = new Intent(Intent.ACTION_VIEW);
//设置intent的数据类型是应用程序application
intent.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android.package-archive");
//为这个新apk开启一个新的activity栈
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//开始安装
startActivity(intent);
//关闭旧版本的应用程序的进程
// android.os.Process.killProcess(android.os.Process.myPid());
})
.setNegativeButton("暂不更新",
(dialog12, whichButton) -> {
// 点击"取消"按钮之后退出程序
// finish();
dialog12.dismiss();
}).create();// 创建
dialog.show();
}
我这里还加了定时检测是偶发有要更新的apk 找到之后关掉定时器
demo里所有到的依赖库
//RxJava,RxAndroid implementation 'io.reactivex.rxjava2:rxjava:2.1.14' implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' //butterknife implementation 'com.jakewharton:butterknife:8.8.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
别忘记加权限~
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
android:name="android.permission.READ_EXTERNAL_STORAGE" />
参照博客 https://blog.csdn.net/qq_32452623/article/details/52280912
https://blog.csdn.net/bzlj2912009596/article/details/78778436
最后奉上项目的地址
点击打开链接
有问题可以提出来共同讨论学习