Intereting Posts

Открытие gpx-файла в Osmand, из другого приложения

У меня есть приложение для Android, которое в основном хранит список файлов gpx, которые сохраняются на телефоне пользователя. Когда пользователь нажимает на имя файла в приложении, он должен предлагать пользователю открыть файл gpx с любыми приложениями маршрутизации, доступными на его телефоне. Сейчас я тестирую с открытием файла в Османде. Проблема в том, что Османд открывает, но тут же рушится.

Код, который пытается открыть файл, следующий:

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> * <?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> * <?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», трек будет отображаться на карте только хорошо, в том числе Путевые точки.

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) 

У Османда не хватает разрешения на чтение этого файла из FileProvider? Другими словами, помогает ли оно разрешить чтение в намерении до вызова функции startActivity:

 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 

(Я не знаю, нужны ли Osmand разрешения на запись. Вы также можете попробовать добавить это: FLAG_GRANT_WRITE_URI_PERMISSION).

Я также предлагаю тщательно перепроверять конфигурацию вашего FileProvider в файлеpathpaths.xml (в директории ресурсов xml). Возможно, что-то вроде этого:

 <paths> <files-path path="images/" name="myimages" /> </paths> 

Например, атрибут вашего пути к файлу указывает на правильный каталог? Являются ли нужные файлы gpx в этом каталоге? ( https://developer.android.com/training/secure-file-sharing/setup-sharing.html )

Еще одна вещь, о которой следует помнить, состоит в том, что строка полномочий в элементе поставщика должна быть уникальной на устройстве. Итак, в этой части вашего 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 трассировку стека для этого сбоя.

— EDIT 08/17/2017 —

Просто для того, чтобы внести некоторые детали в суть этого ответа: поскольку AM доказал и описал в комментариях ниже, фактическое исправление заключалось в том, чтобы явно предоставить необходимые разрешения нескольким конкретным пакетам на устройстве, повторно вызвав 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); } 

Этот подход более подробно описан здесь: https://stackoverflow.com/a/18332000/3482621

Необходимость вызова grantUriPermission (вместо того, чтобы просто полагаться на намерение.addFlags (Intent.FLAG_GRANT_READ_URI_PERMISSION)), похоже, зависит от версии платформы Android, установленной на устройстве. Это описано в отчете о проблемах: https://issuetracker.google.com/issues/37005552