У меня есть собственный тип / расширение файла, с которым я хочу связать свое приложение.
Насколько мне известно, элемент данных создан для этой цели, но я не могу заставить его работать. http://developer.android.com/guide/topics/manifest/data-element.html Согласно документации и множеству сообщений на форуме, это должно работать следующим образом:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:mimeType="application/pdf" />
</intent-filter>
Что ж, не работает. Что я сделал не так? Я просто хочу объявить свой собственный тип файла.
Ответы:
Вам нужно несколько фильтров намерений для решения различных ситуаций, с которыми вы хотите справиться.
Пример 1, обработка HTTP-запросов без mimetypes:
<intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http" /> <data android:host="*" /> <data android:pathPattern=".*\\.pdf" /> </intent-filter>
Обработка с миметическими типами, где суффикс не имеет значения:
<intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http" /> <data android:host="*" /> <data android:mimeType="application/pdf" /> </intent-filter>
Обработка намерений из приложения файлового браузера:
<intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="file" /> <data android:host="*" /> <data android:pathPattern=".*\\.pdf" /> </intent-filter>
источник
Другие решения не работали для меня надежно, пока я не добавил:
android:mimeType="*/*"
До этого в некоторых приложениях работало, в некоторых нет ...
полное решение для меня:
<intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="file" android:host="*" android:pathPattern=".*\\.EXT" android:mimeType="*/*" /> </intent-filter>
источник
mimeType
и». См. Developer.android.com/guide/components/…Ответы Phyrum Tea и yuku уже очень информативны.
Хочу добавить, что начиная с Android 7.0 Nougat изменился способ обмена файлами между приложениями:
Из официальных изменений Android 7.0 :
Если у вас есть собственный файл, заканчивающийся без определенного
mime-type
(или, я думаю, даже с одним), вам, возможно, придется добавить второеscheme
значение к your,intent-filter
чтобы онFileProviders
тоже работал .Пример:
<intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="file" /> <data android:scheme="content" /> <data android:mimeType="*/*" /> <!-- Work around Android's ugly primitive PatternMatcher implementation that can't cope with finding a . early in the path unless it's explicitly matched. --> <data android:host="*" /> <data android:pathPattern=".*\\.sfx" /> <data android:pathPattern=".*\\..*\\.sfx" /> <data android:pathPattern=".*\\..*\\..*\\.sfx" /> <data android:pathPattern=".*\\..*\\..*\\..*\\.sfx" /> <!-- keep going if you need more --> </intent-filter>
Здесь важно добавить
<data android:scheme="content" />
к фильтру.
Мне было трудно узнать об этом небольшом изменении, из-за которого моя активность не открывалась на устройствах Android 7.0, в то время как на старых версиях все было хорошо. Надеюсь, это кому-то поможет.
источник
File(uri.path)
, он выйдет из строя из-заNo such file or directory
- придется обрабатывать этот сценарий по-другому при обновлении для поддержки Nougat +!Мои выводы:
Вам нужно несколько фильтров, чтобы иметь дело с различными способами получения файла. т.е. с помощью вложения Gmail, с помощью файлового менеджера, по HTTP, по FTP ... Все они отправляют очень разные намерения.
И вам нужно отфильтровать намерение, которое запускает вашу активность в коде активности.
В приведенном ниже примере я создал поддельный файл типа new.mrz. И я получил его из вложения Gmail и файлового проводника.
Код активности добавлен в onCreate ():
Intent intent = getIntent(); String action = intent.getAction(); if (action.compareTo(Intent.ACTION_VIEW) == 0) { String scheme = intent.getScheme(); ContentResolver resolver = getContentResolver(); if (scheme.compareTo(ContentResolver.SCHEME_CONTENT) == 0) { Uri uri = intent.getData(); String name = getContentName(resolver, uri); Log.v("tag" , "Content intent detected: " + action + " : " + intent.getDataString() + " : " + intent.getType() + " : " + name); InputStream input = resolver.openInputStream(uri); String importfilepath = "/sdcard/My Documents/" + name; InputStreamToFile(input, importfilepath); } else if (scheme.compareTo(ContentResolver.SCHEME_FILE) == 0) { Uri uri = intent.getData(); String name = uri.getLastPathSegment(); Log.v("tag" , "File intent detected: " + action + " : " + intent.getDataString() + " : " + intent.getType() + " : " + name); InputStream input = resolver.openInputStream(uri); String importfilepath = "/sdcard/My Documents/" + name; InputStreamToFile(input, importfilepath); } else if (scheme.compareTo("http") == 0) { // TODO Import from HTTP! } else if (scheme.compareTo("ftp") == 0) { // TODO Import from FTP! } }
Фильтр вложений Gmail:
<intent-filter android:label="@string/app_name"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="content" /> <data android:mimeType="application/octet-stream" /> </intent-filter>
Фильтр проводника файлов:
<intent-filter android:label="@string/app_name"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="file" /> <data android:pathPattern=".*\\.mrz" /> </intent-filter>
HTTP-фильтр:
<intent-filter android:label="@string/rbook_viewer"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http" /> <data android:pathPattern=".*\\.mrz" /> </intent-filter>
Частные функции, использованные выше:
private String getContentName(ContentResolver resolver, Uri uri){ Cursor cursor = resolver.query(uri, null, null, null, null); cursor.moveToFirst(); int nameIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME); if (nameIndex >= 0) { return cursor.getString(nameIndex); } else { return null; } } private void InputStreamToFile(InputStream in, String file) { try { OutputStream out = new FileOutputStream(new File(file)); int size = 0; byte[] buffer = new byte[1024]; while ((size = in.read(buffer)) != -1) { out.write(buffer, 0, size); } out.close(); } catch (Exception e) { Log.e("MainActivity", "InputStreamToFile exception: " + e.getMessage()); } }
источник
В
pathPattern
<data android:pathPattern=".*\\.pdf" />
не работает, если путь к файлу содержит одну или несколько точек перед ".pdf".
Это будет работать:
<data android:pathPattern=".*\\.pdf" /> <data android:pathPattern=".*\\..*\\.pdf" /> <data android:pathPattern=".*\\..*\\..*\\.pdf" /> <data android:pathPattern=".*\\..*\\..*\\..*\\.pdf" />
Добавьте больше, если хотите поддерживать больше точек.
источник
Я пытался заставить это работать целую вечность и пробовал в основном все предлагаемые решения, но до сих пор не могу заставить Android распознавать определенные расширения файлов. У меня есть фильтр намерений с
"*/*"
типом mimetype, который, похоже, работает, и файловые браузеры теперь перечисляют мое приложение как вариант для открытия файлов, однако теперь мое приложение отображается как вариант для открытия ЛЮБОГО ВИДА файла, хотя Я указал определенные расширения файлов с помощью тега pathPattern. Это заходит так далеко, что даже когда я пытаюсь просмотреть / отредактировать контакт в моем списке контактов, Android спрашивает меня, хочу ли я использовать свое приложение для просмотра контакта, и это лишь одна из многих ситуаций, когда это происходит, ОЧЕНЬ ОЧЕНЬ раздражая.В конце концов я нашел это сообщение групп Google с аналогичным вопросом, на который ответил настоящий разработчик фреймворка Android. Она объясняет, что Android просто ничего не знает о расширениях файлов, только MIME-типы ( https://groups.google.com/forum/#!topic/android-developers/a7qsSl3vQq0 ).
Итак, из того, что я видел, пробовал и читал, Android просто не может отличить расширения файлов, а тег pathPattern - это, по сути, гигантская трата времени и энергии. Если вам повезло, что вам нужны файлы только определенного типа mime (например, текст, видео или аудио), вы можете использовать фильтр намерения с типом mime. Однако если вам нужно конкретное расширение файла или mime-тип, неизвестный Android, вам не повезло.
Если я ошибаюсь в чем-либо из этого, скажите мне, до сих пор я читал все сообщения и пробовал все предлагаемые решения, которые мог найти, но ни одно не сработало.
Я мог бы написать еще одну или две страницы о том, насколько распространены подобные вещи в Android и насколько неприятен опыт разработчиков, но я спасу вас от своих гневных разглагольствований;). Надеюсь, я избавил кого-то от неприятностей.
источник
Маркус Рессель прав. Android 7.0 Nougat больше не разрешает обмен файлами между приложениями с использованием URI файла. Необходимо использовать URI контента. Однако URI контента не позволяет использовать общий путь к файлу, только mime-тип. Таким образом, вы не можете использовать URI контента, чтобы связать приложение с собственным расширением файла.
Drobpox имеет интересное поведение на Android 7.0. Когда он встречает неизвестное расширение файла, он, кажется, формирует намерение URI файла, но вместо запуска намерения он вызывает операционную систему, чтобы узнать, какие приложения могут принять намерение. Если есть только одно приложение, которое может принять этот URI файла, оно затем отправляет явный URI контента непосредственно этому приложению. Таким образом, для работы с Dropbox вам не нужно менять фильтры намерений в вашем приложении. Он не требует фильтра намерений URI контента. Просто убедитесь, что приложение может получать URI контента, а ваше приложение с собственным расширением файла будет работать с Dropbox, как это было до Android 7.0.
Вот пример моего кода загрузки файла, измененного для приема URI контента:
Uri uri = getIntent().getData(); if (uri != null) { File myFile = null; String scheme = uri.getScheme(); if (scheme.equals("file")) { String fileName = uri.getEncodedPath(); myFile = new File(filename); } else if (!scheme.equals("content")) { //error return; } try { InputStream inStream; if (myFile != null) inStream = new FileInputStream(myFile); else inStream = getContentResolver().openInputStream(uri); InputStreamReader rdr = new InputStreamReader(inStream); ... } }
источник
Попробуйте, это поможет вам. Вместо pdf вы также можете использовать другие расширения. Сначала вам нужно добавить разрешение на чтение внешнего хранилища в файле androidmanifest.xml .
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Затем в файле androidmanifest в теге Activity вы добавляете фильтр намерений, как показано ниже.
<action android:name="android.intent.action.SEND" /> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType= "application/pdf" /> <data android:host="*" /> </intent-filter>
Наконец, в вашем коде вы получите путь к файлу pdf, как показано ниже:
Intent intent=getIntent(); if(intent!=null) { String action=intent.getAction(); String type=intent.getType(); if(Intent.ACTION_VIEW.equals(action) && type.endsWith("pdf")) { // Get the file from the intent object Uri file_uri=intent.getData(); if(file_uri!=null) filepath=file_uri.getPath(); else filepath="No file"; } else if(Intent.ACTION_SEND.equals(action) && type.endsWith("pdf")){ Uri uri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM); filepath = uri.getPath(); }
источник
Попробуйте добавить
<action android:name="android.intent.action.VIEW"/>
источник
Для вложения Gmail вы можете использовать:
<intent-filter android:label="@string/app_name"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="content" /> <data android:mimeType="application/pdf" /> <!-- .pdf --> <data android:mimeType="application/msword" /> <!-- .doc / .dot --> <data android:mimeType="application/vnd.openxmlformats-officedocument.wordprocessingml.document" /> <!-- .docx --> <data android:mimeType="application/vnd.ms-excel" /> <!-- .xls / .xlt / .xla --> <data android:mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" /> <!-- .xlsx --> <data android:mimeType="application/vnd.ms-powerpoint" /> <!-- .ppt / .pps / .pot / .ppa --> <data android:mimeType="application/vnd.openxmlformats-officedocument.presentationml.presentation" /> <!-- .pptx --> <data android:mimeType="application/vnd.openxmlformats-officedocument.presentationml.slideshow" /> <!-- .ppsx --> <data android:mimeType="application/zip" /> <!-- .zip --> <data android:mimeType="image/jpeg" /> <!-- .jpeg --> <data android:mimeType="image/png" /> <!-- .png --> <data android:mimeType="image/gif" /> <!-- .gif --> <data android:mimeType="text/plain" /> <!-- .txt / .text / .log / .c / .c++ / ... -->
Добавьте столько типов пантомимы, сколько необходимо. Мне они нужны только для моего проекта.
источник
<!-- Works for Files, Drive and DropBox --> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="file" /> <data android:mimeType="*/*" /> <data android:host="*" /> <data android:pathPattern=".*\\.teamz" /> </intent-filter> <!-- Works for Gmail --> <intent-filter> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.DEFAULT"/> <data android:host="gmail-ls" android:scheme="content" android:mimeType="application/octet-stream"/> </intent-filter>
Обратите внимание, что это приведет к тому, что ваше приложение откроет все вложения файлов Gmail, нет способа обойти это
источник
Тем, у кого возникли проблемы с другими приложениями File Manager \ Explorer, как ответили @yuku и @ phyrum-tea
Это работает с приложением файлового менеджера LG по умолчанию.
<intent-filter android:label="@string/app_name_decrypt"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="file" /> <data android:pathPattern=".*\\.lock" /> <data android:pathPattern=".*\\..*\\.lock" /> <data android:pathPattern=".*\\..*\\..*\\.lock" /> </intent-filter>
но не мог работать с ES File Explorer и другими файловыми менеджерами, поэтому я добавил
android:mimeType="*/*"
тогда он работает с ES Explorer, но файловый менеджер LG не может определить тип файла, поэтому мое решение
<intent-filter android:label="@string/app_name_decrypt"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="file" /> <data android:pathPattern=".*\\.lock" /> <data android:pathPattern=".*\\..*\\.lock" /> <data android:pathPattern=".*\\..*\\..*\\.lock" /> </intent-filter> <intent-filter android:label="@string/app_name_decrypt"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="file"/> <data android:scheme="content" /> <data android:mimeType="*/*" /> <data android:pathPattern=".*\\.lock" /> <data android:pathPattern=".*\\..*\\.lock" /> <data android:pathPattern=".*\\..*\\..*\\.lock" /> </intent-filter>
источник
URI контента ftw и фильтр намерений в манифесте ... если ваши файлы имеют настраиваемое расширение .xyz, добавьте соответствующий тип mime:
<intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:host="*" android:mimeType="application/xyz" android:scheme="content" /> </intent-filter>
Некоторые приложения, такие как электронная почта, по-видимому, преобразовывают расширение в mime-тип. Теперь я могу щелкнуть вложение в электронном письме и открыть его в моем приложении.
источник
Прочтите открывающий файл в котлине:
private fun checkFileOpening(intent: Intent) { if (intent.action == Intent.ACTION_VIEW && (intent.scheme == ContentResolver.SCHEME_FILE || intent.scheme == ContentResolver.SCHEME_CONTENT)) { val text = intent.data?.let { contentResolver.openInputStream(it)?.bufferedReader()?.use(BufferedReader::readText) } } }
источник
Поместите этот фильтр намерений внутри тега активности в манифесте, который вы хотите открыть, касаясь файла:
<intent-filter android:priority="999"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.OPENABLE" /> <data android:host="*" /> <data android:mimeType="application/octet-stream" /> <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.yourextension" /> <data android:pathPattern=".*\\..*\\..*\\..*\\.yourextension" /> <data android:pathPattern=".*\\..*\\..*\\.yourextension" /> <data android:pathPattern=".*\\..*\\.yourextension" /> <data android:pathPattern=".*\\.yourextension" /> <data android:scheme="content" /> </intent-filter>
источник
// Я пробовал этот код. И это хорошо работает. Вы можете использовать этот код, чтобы принять файл PDF.
<intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="application/pdf" /> <data android:pathPattern=".*\\.pdf" /> <data android:pathPattern=".*\\..*\\.pdf" /> <data android:pathPattern=".*\\..*\\..*\\.pdf" /> <data android:pathPattern=".*\\..*\\..*\\..*\\.pdf" /> </intent-filter>
источник