2010-09-21 3 views
78

У меня есть собственный тип/расширение файла, с которым я хочу связать свое приложение.Фильтр намерений Android: связать приложение с расширением файла

Насколько я знаю, элемент данных создан для этой цели, но я не могу заставить его работать. 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> 

Ну, это не работает. Что я сделал не так? Я просто хочу объявить свой собственный тип файла.

ответ

105

Вам нужно несколько фильтров намерений решить другую ситуацию вы хотите обработать.

Пример 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> 

Ручка с 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: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> 
+0

Я думал, что host = "*" может быть опущен, но он стал слишком широким. –

+0

Потребовалось некоторое время, но да, вот так. Спасибо! – Tamas

+2

Жаль, что я не смог дважды проголосовать за этот ответ –

2

Попробуйте добавить

<action android:name="android.intent.action.VIEW"/> 
+0

Теперь, когда вы работаете с заводскими файлами типа application/pdf, как я могу объявить свой собственный тип файла? И когда я говорю тип файла, я имею в виду mimeType;) – Tamas

+0

Какой файл вы хотите, чтобы этот mimetype поймал? Кроме того, открыт ли этот файл из браузера или файлового менеджера или отправлен из другого приложения, которое вы сделали? – magaio

+0

может быть из браузера, почтового клиента, файлового менеджера или где угодно. Или мое собственное приложение ofc :) расширение файла является обычным, задано клиентом. – Tamas

14

pathPattern

<data android:pathPattern=".*\\.pdf" /> 

не работает, если путь к файлу содержит одну или несколько точек перед «.pdf».

Это будет работать:

<data android:pathPattern=".*\\.pdf" /> 
<data android:pathPattern=".*\\..*\\.pdf" /> 
<data android:pathPattern=".*\\..*\\..*\\.pdf" /> 
<data android:pathPattern=".*\\..*\\..*\\..*\\.pdf" /> 

Добавить больше, если вы хотите поддерживать больше точек.

+1

На данный момент это единственный вариант для перехода в подпапки – LokiDroid

+0

Я использую тот же код, но IDE дает мне предупреждение, см. Этот вопрос http://stackoverflow.com/ вопросы/35833776/manifest-custom-file-format-opening-pattern-not-well-formatted? noredirect = 1 # comment59334593_35833776 – AndreaF

42

Другие решения не работают надежно для меня, пока я не добавил:

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> 
+1

wow! это помогло мне. Похоже, что документация по android неверна. Все (схема, хост, путь [Pattern], mimeType) должны быть объявлены для работы – Gavriel

+0

. Вы должны иметь ** оба ** правило с типом mimeType и без него, если вы хотите быть полным. См. Https://developer.android.com/guide/components/intents-filters.html # DataTest –

+0

Что делать, если вы хотите открыть свое файловое приложение из Gmail? –

16

Мои данные:

Вам нужно несколько фильтров для обработки t он использует различные способы получения файла. т.е. с помощью вложения 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> 
  • ЛОГ: Содержание намерения обнаружено: android.intent.action.VIEW: Содержание://gmail-ls/[email protected]/messages/2950/attachments/0.1/BEST/false: application/octet-stream: new.mrz

File Explorer фильтр:

 <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> 
  • LOG: android.intent.action.VIEW: Файл: ///storage/sdcard0/My%20Documents/new.mrz: нуль: новый умысел обнаруженный файл. МСЗ

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()); 
    } 
} 
1

Я пытался заставить это работать целую вечность и пробовал все предлагаемые решения, но до сих пор не может заставить Android распознавать определенные расширения файлов. У меня есть фильтр намерений с типом "*/*" mimetype, который, похоже, работает, и файловые браузеры теперь перечисляют мое приложение в качестве опции для открытия файлов, однако теперь мое приложение показано как опция для открытия ЛЮБОГО ВИДА файла даже хотя я указал конкретные расширения файлов, используя тег pathPattern. Это до сих пор, что даже когда я пытаюсь просмотреть/редактировать контакт в моем списке контактов, Android спрашивает меня, хочу ли я использовать свое приложение для просмотра контакта, и это лишь одна из многих ситуаций, когда это происходит, ОЧЕНЬ ОЧЕНЬ раздражает.

В конце концов я нашел это сообщение в группах google с похожим вопросом, на который ответил фактический инженер Android framework. Она объясняет, что Android просто ничего не знает о расширениях файлов, только MIME-типы (https://groups.google.com/forum/#!topic/android-developers/a7qsSl3vQq0).

Итак, из того, что я видел, пробовал и читал, Android просто не может различать расширения файлов и тег pathPattern - это в основном гигантская трата времени и энергии. Если вам повезло, что вам нужны только файлы определенного типа mime (например, текст, видео или аудио), вы можете использовать фильтр намерений с типом mime. Если вам требуется определенное расширение файла или тип mime, неизвестный Android, однако вам не повезло.

Если я ошибаюсь в отношении любого из этого, скажите мне, я до сих пор читал каждое сообщение и пробовал каждое предлагаемое решение, которое я мог найти, но никто не работал.

Я мог бы написать еще одну или две страницы о том, насколько распространены эти вещи в Android и как навязчивый опыт разработчиков, но я избавлю вас от своих разгневанных разглагольствований;). Надеюсь, я спасла кого-то от неприятностей.

0

Для крепления 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++/... --> 

Добавьте столько типов пантомимы по мере необходимости. Мне нужны только те, для моего проекта.

1
  <!-- 
      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 файлов, нет никакого способа обойти

+0

Это будет обрабатывать каждый файл, отправленный по электронной почте пользователю, а не только **. Teamz ** –

7

The ответивших, данные Phyrum Tea и yuku очень информативно уже.

Я хочу добавить, что, начиная с Android 7,0 Нуга есть изменения в общий доступ к файлам пути между приложениями осуществляется:

От официального Android 7.0 Changes:

для приложений, ориентированных на Android 7.0, в платформе Android применяется политика StrictMode API, которая запрещает публикацию файлов: // URI за пределами вашего приложения. Если удержание, содержащее URI файла, покидает ваше приложение, приложение выходит из строя с исключением FileUriExposedException.

Чтобы поделиться файлами между приложениями, вы должны отправить контент: // URI и предоставить разрешение на временный доступ в URI. Самый простой способ получить это разрешение - , используя класс FileProvider. Для получения дополнительной информации о разрешениях и общих файлах см. Раздел Совместное использование файлов.

Если у вас есть свой собственный пользовательский файл, заканчивающийся без определенного mime-type (или я предполагаю, что даже с одним), вы, возможно, придется добавить второй scheme значение для вашего 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, в то время как все было в порядке на старых версиях. Надеюсь, это поможет кому-то.

3

Markus Ressel является правильным. Android 7.0 Nougat больше не разрешает совместное использование файлов между приложениями с использованием URI файла. Необходимо использовать URI содержимого. Тем не менее, URI контента не разрешает общий доступ к файлу, а только тип mime. Таким образом, вы не можете использовать URI контента, чтобы связать приложение с вашим собственным расширением файла.

Drobpox имеет интересное поведение на Android 7.0. Когда он встречается с неизвестным расширением файла, он, как представляется, формирует намерение URI файла, но вместо запуска намерения он вызывает операционную систему, чтобы узнать, какие приложения могут принять намерение. Если есть только одно приложение, которое может принять этот URI файла, он затем отправляет явный URL-адрес контента непосредственно этому приложению. Поэтому для работы с 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); 
     ... 
    } 
} 
0

Те, кто имеющих проблемы с другими приложениями Диспетчер файлов \ Explorer, как @yuku и @ phyrum чай ответил

Это работает с 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 Проводнике, но файловый менеджер 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> 
0

Content URI FTW, и с намерением фильтра в манифесте ... если ваши файлы иметь пользовательские расширения .xyz, добавить тип соответствия мим:

 <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. Теперь я могу нажать на вложение по электронной почте и открыть его в своем приложении.

Смежные вопросы