我的应用程序包括经典的“共享此应用程序”菜单选项,该选项可以截取两张屏幕截图并通过邮件将其与促销文字一起发送。
从 Java 迁移到 Kotlin 之前它运行良好,但现在在 Kotlin 中它开始抛出异常。
奇怪的是,即使出现异常(可以在 logcat 中看到),该过程也运行良好,应用程序没有崩溃(至少不是以可见的方式)并且共享过程已完成,例如,如果您选择电子邮件 电子邮件与图像一起收到。
清单.xml
<provider
android:name=".helpers.GenericFileProvider"
android:authorities="${applicationId}.GenericFileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
通用文件提供者:
package com.xxx.xxx.helpers
import androidx.core.content.FileProvider
class GenericFileProvider : FileProvider()
provider_paths.xml:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<cache-path name="cache" path="."/>
</paths>
分享文件:
@JvmStatic
fun shareFile(uris: ArrayList<Uri?>?, fileType: String?) {
try {
val share = Intent(Intent.ACTION_SEND_MULTIPLE)
share.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
share.type = fileType
val strSubject = getStringResourceByName("mainmenu_sharethisapp_subject")
share.putExtra(Intent.EXTRA_SUBJECT, strSubject)
share.putParcelableArrayListExtra(Intent.EXTRA_TEXT, uris)
share.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
activity!!.get()!!.startActivity(
Intent.createChooser(
share,
getStringResourceByName("mainmenu_sharethisapp_sharethoughttitle")
)
)
} catch (ex: Exception) {
Toast.makeText(activity!!.get(), ex.message.toString(), Toast.LENGTH_LONG).show()
}
}
图像处理完成:
fun onImageProcessingFinished(ipr: ImageProcessingResult, activity: Activity) {
val uris = ArrayList<Uri?>()
for (file in ipr.screenShotFiles) {
val uri = FileProvider.getUriForFile(activity, activity.packageName + ".GenericFileProvider", file)
if (uri!=null) uris.add(uri)
}
AWDrawerMenu.listener = activity as IActionListeners
AWDrawerMenu.activity = WeakReference(activity)
AWDrawerMenu.shareFile(uris, "image/jpg")
}
例外:
2022-06-16 22:01:08.427 11357-11378/com.xxx.xxx E/DatabaseUtils: Writing exception to parcel
java.lang.SecurityException: Permission Denial: reading com.xxx.xxx.helpers.GenericFileProvider uri content://com.xxx.xxx.GenericFileProvider/cache/xxx.jpg from pid=6474, uid=1000 requires the provider be exported, or grantUriPermission()
at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:820)
at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:684)
at android.content.ContentProvider$Transport.enforceFilePermission(ContentProvider.java:674)
at android.content.ContentProvider$Transport.openTypedAssetFile(ContentProvider.java:548)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:327)
at android.os.Binder.execTransactInternal(Binder.java:1154)
at android.os.Binder.execTransact(Binder.java:1123)
编辑1:
如果我用这个 next 替换 onImageProcessingFinished 方法
fun onImageProcessingFinished(ipr: ImageProcessingResult, activity: Activity) {
val uris = ArrayList<Uri?>()
for (file in ipr.screenShotFiles) {
val uri = FileProvider.getUriForFile(activity, activity.packageName + ".helpers.GenericFileProvider", file)
if (uri!=null) uris.add(uri)
}
AWDrawerMenu.listener = activity as IActionListeners
AWDrawerMenu.activity = WeakReference(activity)
AWDrawerMenu.shareFile(uris, "image/jpg")
}
在 GenericFileProvider 之前添加 .helpers (最后是 GenericFileProvider 的完整包名称),然后抛出以下异常(在这种情况下应用程序 DO 崩溃):
2022-06-16 21:48:10.203 10694-10694/com.xxx.xxx E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.xxx.xxx, PID: 10694
java.lang.IllegalArgumentException: Couldn't find meta-data for provider with authority com.xxx.xxx.helpers.GenericFileProvider
at androidx.core.content.FileProvider.parsePathStrategy(FileProvider.java:662)
at androidx.core.content.FileProvider.getPathStrategy(FileProvider.java:635)
at androidx.core.content.FileProvider.getUriForFile(FileProvider.java:441)
at com.xxx.xxx.component.drawer.AWDrawer$Companion.onImageProcessingFinished(AWDrawer.kt:294)
at com.xxx.xxx.activities.main.MainActivity.onImageProcessingFinished(MainActivity.kt:448)
at com.xxx.xxx.activities.main.MainActivity.onShareThisApp$lambda-6(MainActivity.kt:443)
at com.xxx.xxx.activities.main.MainActivity.$r8$lambda$c-xNLWLGog-3ah1DvHN4y6HCHsw(Unknown Source:0)
at com.xxx.xxx.activities.main.MainActivity$$ExternalSyntheticLambda3.onComplete(Unknown Source:4)
at com.xxx.xxx.helpers.TaskRunner.executeAsync$lambda-1$lambda-0(TaskRunner.kt:24)
at com.xxx.xxx.helpers.TaskRunner.$r8$lambda$ItjAcdIefpXj05LbTtje15JKSPM(Unknown Source:0)
at com.xxx.xxx.helpers.TaskRunner$$ExternalSyntheticLambda0.run(Unknown Source:4)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
我最终发现我遇到了与此处描述的完全相同的问题:
幸运的是,完全相同的解决方案对我有用。
我必须更换这个:
@JvmStatic
fun shareFile(uris: ArrayList<Uri?>?, fileType: String?) {
try {
val share = Intent(Intent.ACTION_SEND_MULTIPLE)
share.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
share.type = fileType
val strSubject = getStringResourceByName("mainmenu_sharethisapp_subject")
share.putExtra(Intent.EXTRA_SUBJECT, strSubject)
share.putParcelableArrayListExtra(Intent.EXTRA_TEXT, uris)
share.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
activity!!.get()!!.startActivity(
Intent.createChooser(
share,
getStringResourceByName("mainmenu_sharethisapp_sharethoughttitle")
)
)
activity!!.get()!!.startActivity(share)
} catch (ex: Exception) {
Toast.makeText(activity!!.get(), ex.message.toString(), Toast.LENGTH_LONG).show()
}
}
通过这个:
@JvmStatic
fun shareFile(uris: ArrayList<Uri?>?, fileType: String?) {
try {
val share = Intent(Intent.ACTION_SEND_MULTIPLE)
share.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
share.type = fileType
val strSubject = getStringResourceByName("mainmenu_sharethisapp_subject")
share.putExtra(Intent.EXTRA_SUBJECT, strSubject)
share.putParcelableArrayListExtra(Intent.EXTRA_TEXT, uris)
share.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
/*activity!!.get()!!.startActivity(
Intent.createChooser(
share,
getStringResourceByName("mainmenu_sharethisapp_sharethoughttitle")
)
)*/
activity!!.get()!!.startActivity(share)
} catch (ex: Exception) {
Toast.makeText(activity!!.get(), ex.message.toString(), Toast.LENGTH_LONG).show()
}
}
选择器看起来有点不同(不知道为什么),但它有效。
编辑1:
好的,最终的工作代码:
@JvmStatic
fun shareFile(uris: ArrayList<Uri?>?, fileType: String?) {
try {
val strSubject = getStringResourceByName("mainmenu_sharethisapp_subject")
val strMessage = getStringResourceByName("mainmenu_sharethisapp_message")
val intent = Intent()
intent.type = fileType
intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
intent.putExtra(Intent.EXTRA_SUBJECT, strSubject)
intent.putExtra(Intent.EXTRA_TEXT, strMessage)
if (uris!!.size == 0) {
return
} else if (uris.size == 1) {
val uri = uris[0]!!
intent.action = Intent.ACTION_SEND
intent.putExtra(Intent.EXTRA_STREAM, uri)
intent.clipData = ClipData.newRawUri("", uri)
} else {
intent.action = Intent.ACTION_SEND_MULTIPLE
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris)
val clipData = ClipData.newRawUri("", uris[0])
for (i in 1 until uris.size) {
val uri = uris[i]!!
clipData.addItem(ClipData.Item(uri))
}
intent.clipData = clipData
}
activity!!.get()!!.startActivity(
Intent.createChooser(
intent, getStringResourceByName("mainmenu_sharethisapp_sharethoughttitle")
)
)
} catch (ex: Exception) {
Toast.makeText(activity!!.get(), ex.message.toString(), Toast.LENGTH_LONG).show()
}
}
我遇到了
@Transactional
的问题,并设法使用 open class
而不是仅仅使用 class
来解决它