安卓关联后缀文件打开
安卓是通过添加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打开是先调用MainActivity的onCreate方法,还没有走到Flutter的Main方法中,导致我们的Platform Channels没有初始化,如果直接调用Channel来通信的话是没有用的,会导致第一次打开app无法导入文件的情况,并且和Flutter端通信的操作必须要放在主线程
PPS: 更好的做法是等Flutter那边的Method Channel初始化好了之后给原生端发消息,然后原生端再来处理分享过来的Intent