从另一个应用程序在 Osmand 中打开 gpx 文件
Opening gpx file in Osmand, from another application
我有一个 Android 应用程序,它主要存储保存在用户 phone 上的 gpx 文件列表。当用户单击应用程序中的文件名时,它应该提示用户使用他 phone 上可用的任何路由应用程序打开 gpx 文件。现在我正在测试在 Osmand 中打开文件。问题是,Osmand 正在打开,但随后立即崩溃。
尝试打开文件的代码是这样的:
File gpxFile = new File(Path);
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
Uri gpxUri = FileProvider.getUriForFile(view.getContext(), AUTHORITY, gpxFile);
intent.setDataAndType(gpxUri, "application/gpx+xml");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
gpx 文件都是这样的:
<?xml version="1.0"?>
<gpx creator="{CREATOR}" version="1.1" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
<wpt lat="{LAT_1}" lon="{LON_1}">
<name>{WPT_NAME_1}</name>
</wpt>
...
<wpt lat="{LAT_N}" lon="{LON_N}">
<name>{WPT_NAME_N}</name>
</wpt>
<trk>
<name>{TRACK_NAME}</name>
<trkseg>
<trkpt lat="{LAT_1}" lon="{LON_1}"></trkpt>
...
<trkpt lat="{LAT_N}" lon="{LON_N}"></trkpt>
</trkseg>
</trk>
</gpx>
起初我以为是 gpx 文件的格式有问题,但如果我手动打开 Osmand 并尝试使用 "Configure map" -> "Gpx track" 导入文件,曲目显示地图上就好了,包括waypoints.
LE:这是我在 Osmand 尝试启动时遇到的错误:
08-16 17:28:00.524 5681-5762/? E/net.osmand: RenderingRuleProperty Rendering parse in strokeWidth_2
08-16 17:28:00.524 5681-5762/? E/net.osmand: RenderingRuleProperty Rendering parse in strokeWidth_2
08-16 17:28:01.259 5681-5681/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: net.osmand, PID: 5681
java.lang.RuntimeException: Unable to resume activity {net.osmand/net.osmand.plus.activities.MapActivity}: java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{3ddadf4 5681:net.osmand/u0a203} (pid=5681, uid=10203) that is not exported from uid 10275
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3788)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3828)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2991)
at android.app.ActivityThread.-wrap14(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1635)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6692)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
Caused by: java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{3ddadf4 5681:net.osmand/u0a203} (pid=5681, uid=10203) that is not exported from uid 10275
at android.os.Parcel.readException(Parcel.java:1693)
at android.os.Parcel.readException(Parcel.java:1646)
at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:4861)
at android.app.ActivityThread.acquireProvider(ActivityThread.java:5958)
at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2452)
at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1521)
at android.content.ContentResolver.query(ContentResolver.java:520)
at android.content.ContentResolver.query(ContentResolver.java:478)
at net.osmand.plus.helpers.GpxImportHelper.getNameFromContentUri(GpxImportHelper.java:108)
at net.osmand.plus.helpers.GpxImportHelper.handleContentImport(GpxImportHelper.java:69)
at net.osmand.plus.activities.MapActivity.onResume(MapActivity.java:617)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1277)
at android.app.Activity.performResume(Activity.java:7058)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3765)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3828)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2991)
at android.app.ActivityThread.-wrap14(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1635)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6692)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
Osmand 是否没有从 FileProvider 读取该文件的权限?换句话说,在调用 startActivity 之前在意图中授予读取权限是否有帮助:
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
(我不知道 Osmand 是否也需要写权限。您也可以尝试添加它:FLAG_GRANT_WRITE_URI_PERMISSION)。
我还建议仔细检查 filepaths.xml(在 'xml' 资源目录中)中的 FileProvider 配置。大概是这样的:
<paths>
<files-path path="images/" name="myimages" />
</paths>
例如您的文件路径属性是否指向正确的目录?该目录中是否有所需的 gpx 文件? (https://developer.android.com/training/secure-file-sharing/setup-sharing.html)
另一件要记住的事情是,provider 元素中的权限字符串在设备上必须是唯一的。因此,在您的 AndroidManifest 的这一部分,确保您已将 "com.example.myapp.fileprovider" 替换为您的应用独有的内容:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
如果这没有帮助,我只能建议观察设备的 logcat 输出,看看 Osmand 是否为这次崩溃写了堆栈跟踪。
--- 编辑 2017 年 8 月 17 日 ---
只是为了在这个答案的正文中添加一些细节:如 A.M。在下面的评论中得到证明和描述,实际的修复是通过在循环中重复调用 context.grantUriPermission 来显式授予设备上多个特定包的必要权限,如下所示:
//grant permisions for all apps that can handle given intent
List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
此方法在此处有更多记录:
是否需要调用 grantUriPermission(而不是仅仅依赖于 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION))似乎取决于设备上安装的 Android 平台版本。这在此处的问题报告中进行了描述:https://issuetracker.google.com/issues/37005552
我有一个 Android 应用程序,它主要存储保存在用户 phone 上的 gpx 文件列表。当用户单击应用程序中的文件名时,它应该提示用户使用他 phone 上可用的任何路由应用程序打开 gpx 文件。现在我正在测试在 Osmand 中打开文件。问题是,Osmand 正在打开,但随后立即崩溃。
尝试打开文件的代码是这样的:
File gpxFile = new File(Path);
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
Uri gpxUri = FileProvider.getUriForFile(view.getContext(), AUTHORITY, gpxFile);
intent.setDataAndType(gpxUri, "application/gpx+xml");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
gpx 文件都是这样的:
<?xml version="1.0"?>
<gpx creator="{CREATOR}" version="1.1" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
<wpt lat="{LAT_1}" lon="{LON_1}">
<name>{WPT_NAME_1}</name>
</wpt>
...
<wpt lat="{LAT_N}" lon="{LON_N}">
<name>{WPT_NAME_N}</name>
</wpt>
<trk>
<name>{TRACK_NAME}</name>
<trkseg>
<trkpt lat="{LAT_1}" lon="{LON_1}"></trkpt>
...
<trkpt lat="{LAT_N}" lon="{LON_N}"></trkpt>
</trkseg>
</trk>
</gpx>
起初我以为是 gpx 文件的格式有问题,但如果我手动打开 Osmand 并尝试使用 "Configure map" -> "Gpx track" 导入文件,曲目显示地图上就好了,包括waypoints.
LE:这是我在 Osmand 尝试启动时遇到的错误:
08-16 17:28:00.524 5681-5762/? E/net.osmand: RenderingRuleProperty Rendering parse in strokeWidth_2
08-16 17:28:00.524 5681-5762/? E/net.osmand: RenderingRuleProperty Rendering parse in strokeWidth_2
08-16 17:28:01.259 5681-5681/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: net.osmand, PID: 5681
java.lang.RuntimeException: Unable to resume activity {net.osmand/net.osmand.plus.activities.MapActivity}: java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{3ddadf4 5681:net.osmand/u0a203} (pid=5681, uid=10203) that is not exported from uid 10275
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3788)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3828)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2991)
at android.app.ActivityThread.-wrap14(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1635)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6692)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
Caused by: java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{3ddadf4 5681:net.osmand/u0a203} (pid=5681, uid=10203) that is not exported from uid 10275
at android.os.Parcel.readException(Parcel.java:1693)
at android.os.Parcel.readException(Parcel.java:1646)
at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:4861)
at android.app.ActivityThread.acquireProvider(ActivityThread.java:5958)
at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2452)
at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1521)
at android.content.ContentResolver.query(ContentResolver.java:520)
at android.content.ContentResolver.query(ContentResolver.java:478)
at net.osmand.plus.helpers.GpxImportHelper.getNameFromContentUri(GpxImportHelper.java:108)
at net.osmand.plus.helpers.GpxImportHelper.handleContentImport(GpxImportHelper.java:69)
at net.osmand.plus.activities.MapActivity.onResume(MapActivity.java:617)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1277)
at android.app.Activity.performResume(Activity.java:7058)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3765)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3828)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2991)
at android.app.ActivityThread.-wrap14(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1635)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6692)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
Osmand 是否没有从 FileProvider 读取该文件的权限?换句话说,在调用 startActivity 之前在意图中授予读取权限是否有帮助:
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
(我不知道 Osmand 是否也需要写权限。您也可以尝试添加它:FLAG_GRANT_WRITE_URI_PERMISSION)。
我还建议仔细检查 filepaths.xml(在 'xml' 资源目录中)中的 FileProvider 配置。大概是这样的:
<paths>
<files-path path="images/" name="myimages" />
</paths>
例如您的文件路径属性是否指向正确的目录?该目录中是否有所需的 gpx 文件? (https://developer.android.com/training/secure-file-sharing/setup-sharing.html)
另一件要记住的事情是,provider 元素中的权限字符串在设备上必须是唯一的。因此,在您的 AndroidManifest 的这一部分,确保您已将 "com.example.myapp.fileprovider" 替换为您的应用独有的内容:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
如果这没有帮助,我只能建议观察设备的 logcat 输出,看看 Osmand 是否为这次崩溃写了堆栈跟踪。
--- 编辑 2017 年 8 月 17 日 ---
只是为了在这个答案的正文中添加一些细节:如 A.M。在下面的评论中得到证明和描述,实际的修复是通过在循环中重复调用 context.grantUriPermission 来显式授予设备上多个特定包的必要权限,如下所示:
//grant permisions for all apps that can handle given intent
List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
此方法在此处有更多记录:
是否需要调用 grantUriPermission(而不是仅仅依赖于 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION))似乎取决于设备上安装的 Android 平台版本。这在此处的问题报告中进行了描述:https://issuetracker.google.com/issues/37005552