Android 插上U盘自动更新

插上U盘自动更新的原理

1、检测是否有指定路径下的文件夹

String apkPath = "/storage/usbhost1/apk";//本地APK的根目录,不同的屏路径不同

我这里是将要更新的apk文件放在U盘里apk这个文件夹下(不同的屏,路径不同

2、找出该文件夹下的所有.apk文件,并判断是是否是要更新apk文件

/**
 * 获取APK文件的名字
 *
 * @param usbPath APKU盘里的根目录
 */
private String getApkName(String usbPath) {
    ArrayList datas = 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;
}

3、获取U盘中apk的绝对路径,并获取apk的版本信息

      这里主要是获取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;
        /* icon1icon2其实是一样的 */
        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");
    }

}

4、将获取到的apk版本信息个本地的版本信息做对比!判断是否是最新版本

/**
 * 获取版本号
 *
 * @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();
    }
}

5、安装U盘里的APK文件

 /**
     * 安装APK
     *
     * @param apkPath UAPK文件绝对路径
     */
    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 找到之后关掉定时器

Android 插上U盘自动更新_第1张图片

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


最后奉上项目的地址

点击打开链接

以上是个人 apk U盘更新解决方案~(大佬勿喷)

有问题可以提出来共同讨论学习


你可能感兴趣的:(Android)