安卓关联后缀文件打开

安卓是通过添加Intent来实现的

AndroidManifest.xml文件中activity标签中添加

    <intent-filter android:label="导入到享阅">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
        <data android:mimeType="application/epub+zip" />
        <data android:mimeType="application/x-rar-compressed" />
        <data android:mimeType="application/zip" />
        <data android:mimeType="application/x-7z-compressed" />
    </intent-filter>

其中android:label代表打开文件时我们的app图标下面的描述

<action android:name="android.intent.action.VIEW" />是根据我们设置的数据类型来调用我们的Activity来处理显示

<category android:name="android.intent.category.DEFAULT" />

Set if the activity should be an option for the default action (center press) to perform on a piece of data. Setting this will hide from the user any activities without it set when performing an action on some data. Note that this is normally -not- set in the Intent when initiating an action -- it is for use in intent filters specified in packages.

是设置当前Activity是否应该作为一个段数据执行的选项的默认操作,用户对数据进行操作时,可以通过制定的intent过滤器来匹配

    <data android:mimeType="text/plain" />
    <data android:mimeType="application/epub+zip" />
    <data android:mimeType="application/x-rar-compressed" />
    <data android:mimeType="application/zip" />
    <data android:mimeType="application/x-7z-compressed" />

就是通过制定mimeType来确定到底处理哪些数据

如果有自定义数据,不知道mimeType的,可以通过设置通配符*/*处理所有文件

然后给每个data设置pathPattern来过滤需要处理的文件类型,例如

    <data android:mimeType="*/*"/>
    <data android:pathPattern=".*\\.rar"/>
    <data android:pathPattern=".*\\.txt"/>
    <data android:pathPattern=".*\\.7z"/>
    <data android:pathPattern=".*\\.epub"/>
    <data android:pathPattern=".*\\.zip"/>

处理逻辑

MainActivity.kt中重写onNewIntent方法

    override fun onNewIntent(intent: Intent) {
        handleShared(intent)
    }

每一次启动Activity就会走到这个方法获取到Intent

但是第一次打开可能不会走这个方法,所以在onCreate方法中也需要调用一次handleShared处理第一次打开的情况,handleShared需要的Intent参数可以直接通过系统的getIntent()方法获取到Intent

    private fun handleShared(i: Intent?) {
        val intent: Intent? = i ?: getIntent()
        //处理逻辑
    }

Intent中就可以获取到对应的action,type,Uri等信息

    val action: String? = intent?.action
    val type: String? = intent?.type
    val uri: Uri? = intent?.data

然后通过contentResolver检索数据库,获取到文件名

    val cursor: Cursor? = contentResolver.query(uri, null, null, null, null)
    //将游标移动到第一个,不然是-1会越界
    cursor?.moveToFirst()
    val nameIndex: Int? = cursor?.getColumnIndex(OpenableColumns.DISPLAY_NAME)
    val name: String? = cursor?.getString(nameIndex!!)

再通过Uri直接将文件复制到我们的app内部的文件夹中

    // 创建目标文件
    val outputFile: File = FileUtil.createWifiTransferFile(name, false)
    val fis: InputStream? = contentResolver.openInputStream(uri)
    val fos = FileOutputStream(outputFile)
    val buffer = ByteArray(1024)
    while (true) {
        val byteRead: Int? = fis?.read(buffer)
            if (byteRead == -1) {
                break
            }
            if (byteRead != null) {
                fos.write(buffer, 0, byteRead)
            }
        }
    fos.close()

PS:并且发送到Flutter端的话需要延迟处理,因为app打开是先调用MainActivityonCreate方法,还没有走到Flutter的Main方法中,导致我们的Platform Channels没有初始化,如果直接调用Channel来通信的话是没有用的,会导致第一次打开app无法导入文件的情况,并且和Flutter端通信的操作必须要放在主线程

PPS: 更好的做法是等Flutter那边的Method Channel初始化好了之后给原生端发消息,然后原生端再来处理分享过来的Intent

posted @ 2023-02-15 17:26  R1cardo  阅读(189)  评论(0编辑  收藏  举报