Android-功能实现-001-Android12实现U盘更新

12 阅读2分钟

Android12实现插入U盘更新Apk

1.添加权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 安装权限 -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

2.在res/xml文件夹中创建 file_paths.xml 物理地址文件. 

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="files_root"
        path="Android/data/com.ruihan.handrehabilitation/" />
    <external-path
        name="external_storage_root"
        path="." />
    <!--root-path代表/也就是Android设备的根目录,该目录下包含着手机内部存储器,外置SD卡等所有文件的目录。-->
    <root-path
        name="root"
        path="/" />
</paths>

在AndroidMaindest中引用

<permission-group android:name="${applicationId}.andpermission" />
 
<application>
<provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
</application>

3.静态方式

3.1创建一个广播,进行全局广播监听

public class UsbUpGradeReceiver extends BroadcastReceiver {
    private final static String U_DISK_FILE_NAME = "包名.apk";
 
    @Override
    public void onReceive(Context context, Intent intent) {
        switch (intent.getAction()) {
            case Intent.ACTION_MEDIA_MOUNTED:
                // 获取挂载路径, 读取U盘文件
                Uri uri = intent.getData();
                if (uri != null) {
                    String filePath = uri.getPath();
                    File rootFile = new File(filePath);
                    for (File file : rootFile.listFiles()) {
                        // 文件列表,进行相应操作...
                        if (file.getName().equals(U_DISK_FILE_NAME)) {
                            try {
                                String authority = context.getApplicationContext().getPackageName() + ".fileprovider";
                                Uri fileUri = FileProvider.getUriForFile(context, authority, file);
 
                                PackageManager pm = context.getPackageManager();
 
                                PackageInfo pkgInfo = pm.getPackageArchiveInfo(file.getPath(), PackageManager.GET_ACTIVITIES);
 
                                if (pkgInfo != null) {
                                    ApplicationInfo appInfo = pkgInfo.applicationInfo;
 
                                    PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
                                    LogUtils.e(info.packageName + " " + info.versionName + " " + info.versionCode);
                                    if (appInfo.packageName.equals(info.packageName)) {
                                        if (pkgInfo.versionCode > info.versionCode) {
                                            Intent intents = new Intent(Intent.ACTION_VIEW);
                                            intents.setDataAndType(fileUri, "application/vnd.android.package-archive");
                                            intents.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                            intents.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                                            context.startActivity(intents);
                                        } else {
                                            ToastUtils.showLong("当前需要安装的apk小于当前版本,请检查apk文件");
                                        }
                                    } else ToastUtils.showLong("当前需要安装apk不正确,请检查apk文件!");
                                }
                                break;
                            } catch (PackageManager.NameNotFoundException e) {
                                throw new RuntimeException(e);
                            }
                        }
                    }
                }
                break;
        }
    }
}

3.2 注册全局广播,并添加相应监听事件

<receiver
            android:name=".UsbUpGradeReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MEDIA_CHECKING" />
                <action android:name="android.intent.action.MEDIA_MOUNTED" />
                <action android:name="android.intent.action.MEDIA_EJECT" />
                <action android:name="android.intent.action.MEDIA_UNMOUNTED" />
 
                <data android:scheme="file" />
            </intent-filter>
        </receiver>

4.动态方式


 class XXX{
 

    private var mReceiver: UdiskReceiver? = UdiskReceiver()
    
    //U盘更新
    private fun uUpdateListener() {
        val filter = IntentFilter()
        filter.addAction("android.hardware.usb.action.USB_STATE")
        filter.addAction("android.hardware.action.USB_DISCONNECTED")
        filter.addAction("android.hardware.action.USB_CONNECTED")
        filter.addAction("android.intent.action.UMS_CONNECTED")
        filter.addAction("android.intent.action.UMS_DISCONNECTED")

        filter.addAction(Intent.ACTION_MEDIA_CHECKING)
        filter.addAction(Intent.ACTION_MEDIA_MOUNTED)
        filter.addAction(Intent.ACTION_MEDIA_EJECT)
        filter.addAction(Intent.ACTION_MEDIA_REMOVED)
        filter.addDataScheme("file") // 系统中每个组件,如果想收取隐式事件(未指定接收者),则必须声明自己的IntentFilter(自我介绍,我对什么样的信件感兴趣)。
        registerReceiver(mReceiver, filter)
    }
   
   //U盘插拔监听
    inner class UdiskReceiver : BroadcastReceiver() {
        override fun onReceive(arg0: Context, arg1: Intent) {
            val action = arg1.action
            if (action == Intent.ACTION_MEDIA_CHECKING) {
                // Toast.makeText(getApplicationContext(), "正在挂载U盘",
                // Toast.LENGTH_SHORT).show();
            } else if (action == Intent.ACTION_MEDIA_MOUNTED) {
                //todo 这里兼容GenStar设备
//                String uPanPath = arg1.getData().getPath() + "/DEMO_v10__1.apk";

                val uPanPath = arg1.data!!.path + "/DEMO_v10__1.apk"
                LogUtils.e("U盘:$uPanPath")

                val fileExists = FileUtils.isFileExists(File(uPanPath))
                LogUtils.e("U盘apk:$fileExists")
                if (fileExists) {
                    showUpdateDialog(uPanPath)
                }
            } else if (action == Intent.ACTION_MEDIA_EJECT) {
                LogUtils.e("U盘移除")
            }
        }
    }
    
    
    fun showUpdateDialog(uPanPath: String) {
        val dialog: Dialog = AlertDialog.Builder(this@AuthActivity)
            .setTitle("发现软件")
            .setMessage("是否更新") // 设置内容
            .setPositiveButton(
                "更新"
            )  // 设置确定按钮
            { dialog, which ->
                val fileName = uPanPath

                val file: File = File(fileName)
                try {
                    val authority: String =
                        getApplicationContext().getPackageName() + ".fileprovider"
                    val fileUri = FileProvider.getUriForFile(this, authority, file)


                    val intents = Intent(Intent.ACTION_VIEW)
                    intents.setDataAndType(
                        fileUri,
                        "application/vnd.android.package-archive"
                    )
                    intents.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                    intents.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                    startActivity(intents)

                } catch (e: PackageManager.NameNotFoundException) {
                    throw RuntimeException(e)
                }


            }
            .setNegativeButton(
                "暂不更新"
            ) { dialog, whichButton -> // 点击"取消"按钮之后退出程序
                finish()
            }.create() // 创建

        dialog.show()
    }

   
    override fun onDestroy() {
        super.onDestroy()
        NetStatusBus.getInstance().unregister(this@AuthActivity);//网络状态监听
        unregisterReceiver(mReceiver)

    }

 }