Mam niestandardowy typ / rozszerzenie pliku, z którym chcę powiązać moją aplikację.
O ile wiem, element danych jest przeznaczony do tego celu, ale nie mogę go uruchomić. http://developer.android.com/guide/topics/manifest/data-element.html Zgodnie z dokumentacją i wieloma postami na forum powinno to działać tak:
<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>
Cóż, to nie działa. Co zrobiłem źle? Chcę po prostu zadeklarować własny typ pliku.
Odpowiedzi:
Potrzebujesz wielu filtrów intencji, aby zająć się różnymi sytuacjami, które chcesz rozwiązać.
Przykład 1, obsługa żądań http bez typów MIME:
<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>
Obsługuj z typami MIME, gdzie przyrostek nie ma znaczenia:
<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>
Obsługuj intencję z aplikacji przeglądarki plików:
<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>
źródło
Pozostałe rozwiązania nie działały u mnie niezawodnie, dopóki nie dodałem:
android:mimeType="*/*"
Wcześniej działało w niektórych aplikacjach, w niektórych nie ...
kompletne rozwiązanie dla mnie:
<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>
źródło
mimeType
i jedną bez, jeśli chcesz być kompletny. Zobacz developer.android.com/guide/components/…Odpowiedzi udzielone przez Phyrum Tea i yuku są już bardzo pouczające.
Chcę dodać, że począwszy od Androida 7.0 Nougat nastąpiła zmiana w sposobie obsługi udostępniania plików między aplikacjami:
Z oficjalnych zmian Androida 7.0 :
Jeśli masz własny niestandardowy plik kończący się bez określonego
mime-type
(lub chyba nawet jednym), być może będziesz musiał dodać drugąscheme
wartość do swojego,intent-filter
aby działałFileProviders
również.Przykład:
<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>
Ważną rzeczą jest tutaj dodanie
<data android:scheme="content" />
do filtra.
Trudno mi było dowiedzieć się o tej drobnej zmianie, która uniemożliwiła mi otwieranie się na urządzeniach z Androidem 7.0, podczas gdy wszystko było w porządku na starszych wersjach. Mam nadzieję, że to komuś pomoże.
źródło
File(uri.path)
, ulegnie awarii z powoduNo such file or directory
- będzie musiał obsłużyć ten scenariusz inaczej podczas aktualizacji do obsługi Nougat +!Moje ustalenia:
Potrzebujesz kilku filtrów, aby poradzić sobie z różnymi sposobami pobierania pliku. tj. przez załączniki do Gmaila, przez eksplorator plików, przez HTTP, przez FTP ... Wszystkie wysyłają bardzo różne intencje.
I musisz odfiltrować intencję, która wyzwala twoją aktywność w kodzie aktywności.
W poniższym przykładzie utworzyłem fałszywy typ pliku new.mrz. Pobrałem go z załącznika Gmaila i eksploratora plików.
Kod działania dodany w 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! } }
Filtr załączników Gmaila:
<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>
Filtr eksploratora plików:
<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>
Filtr 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>
Funkcje prywatne użyte powyżej:
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()); } }
źródło
Plik
pathPattern
<data android:pathPattern=".*\\.pdf" />
nie działa, jeśli ścieżka pliku zawiera jedną lub więcej kropek przed „.pdf”.
To zadziała:
<data android:pathPattern=".*\\.pdf" /> <data android:pathPattern=".*\\..*\\.pdf" /> <data android:pathPattern=".*\\..*\\..*\\.pdf" /> <data android:pathPattern=".*\\..*\\..*\\..*\\.pdf" />
Dodaj więcej, jeśli chcesz obsługiwać więcej kropek.
źródło
Próbowałem, aby to działało od lat i wypróbowałem wszystkie sugerowane rozwiązania i nadal nie mogę sprawić, by Android rozpoznał określone rozszerzenia plików. Mam filtr intencji z
"*/*"
typem MIME, który jest jedyną rzeczą, która wydaje się działać, a przeglądarki plików wyświetlają teraz moją aplikację jako opcję otwierania plików, jednak moja aplikacja jest teraz wyświetlana jako opcja do otwierania DOWOLNEGO RODZAJU pliku, mimo że Określone rozszerzenia plików zostały określone za pomocą znacznika pathPattern. To sięga tak daleko, że nawet gdy próbuję wyświetlić / edytować kontakt na mojej liście kontaktów, Android pyta mnie, czy chcę użyć mojej aplikacji do wyświetlenia kontaktu, a to tylko jedna z wielu sytuacji, w których to się dzieje, BARDZO BARDZO irytujące.W końcu znalazłem ten post w grupach Google z podobnym pytaniem, na które odpowiedział prawdziwy inżynier platformy Android. Wyjaśnia, że Android po prostu nie wie nic o rozszerzeniach plików, tylko o typach MIME ( https://groups.google.com/forum/#!topic/android-developers/a7qsSl3vQq0 ).
Więc z tego, co widziałem, wypróbowałem i przeczytałem, Android po prostu nie może odróżnić rozszerzeń plików od tagu pathPattern to w zasadzie gigantyczna strata czasu i energii. Jeśli masz szczęście, że potrzebujesz tylko plików określonego typu MIME (powiedzmy tekst, wideo lub audio), możesz użyć filtru intencji z typem MIME. Jeśli potrzebujesz określonego rozszerzenia pliku lub typu MIME nieznanego przez Androida, nie masz szczęścia.
Jeśli się mylę, powiedz mi, do tej pory przeczytałem każdy post i wypróbowałem wszystkie proponowane rozwiązania, które mogłem znaleźć, ale żadne nie zadziałało.
Mógłbym napisać kolejną stronę lub dwie o tym, jak powszechne są tego typu rzeczy w Androidzie i jak schrzanione jest doświadczenie programisty, ale oszczędzę ci moich gniewnych tyrad;). Mam nadzieję, że zaoszczędziłem komuś kłopotów.
źródło
Markus Ressel ma rację. Android 7.0 Nougat nie pozwala już na udostępnianie plików między aplikacjami przy użyciu identyfikatora URI pliku. Należy użyć identyfikatora URI treści. Jednak identyfikator URI treści nie pozwala na udostępnianie ścieżki pliku, a jedynie typ MIME. Nie możesz więc używać identyfikatora URI treści do powiązania aplikacji z własnym rozszerzeniem pliku.
Drobpox ma ciekawe zachowanie na Androidzie 7.0. Kiedy napotyka nieznane rozszerzenie pliku, wydaje się, że tworzy intencję identyfikatora URI pliku, ale zamiast uruchamiać intencję, wywołuje system operacyjny, aby dowiedzieć się, które aplikacje mogą zaakceptować tę intencję. Jeśli istnieje tylko jedna aplikacja, która może zaakceptować ten identyfikator URI pliku, wówczas wysyła jawny identyfikator URI treści bezpośrednio do tej aplikacji. Aby pracować z Dropbox, nie musisz zmieniać filtrów intencji w swojej aplikacji. Nie wymaga filtra intencji zawartości URI. Upewnij się tylko, że aplikacja może odbierać identyfikator URI treści, a Twoja aplikacja z własnym rozszerzeniem pliku będzie współpracować z Dropbox, tak jak przed Androidem 7.0.
Oto przykład kodu ładowania mojego pliku zmodyfikowanego tak, aby akceptował identyfikator URI treści:
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); ... } }
źródło
Spróbuj tego, ale to ci pomoże. Zamiast pdf możesz użyć innych rozszerzeń. Najpierw musisz dodać uprawnienia do odczytu zewnętrznej pamięci w pliku androidmanifest.xml .
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Następnie w pliku androidmanifest w tagu Activity dodajesz filtr intencji, jak pokazano poniżej.
<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>
Na koniec w kodzie otrzymasz ścieżkę do pliku pdf, jak pokazano poniżej:
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(); }
źródło
Spróbuj dodać
<action android:name="android.intent.action.VIEW"/>
źródło
W przypadku załącznika Gmaila możesz użyć:
<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++ / ... -->
Dodaj dowolną liczbę typów MIME. Potrzebuję ich tylko do mojego projektu.
źródło
<!-- 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>
Zwróć uwagę, że w ten sposób Twoja aplikacja otworzy wszystkie załączniki plików Gmaila, nie ma sposobu na obejście tego
źródło
Odpowiedzieli ci, którzy mają problem z innymi aplikacjami File Manager \ Explorer, jak @yuku i @ phyrum-tea
Działa to z domyślną aplikacją menedżera plików 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>
ale nie mogłem współpracować z ES File Explorer i innymi menedżerami plików, więc dodałem
android:mimeType="*/*"
to działa z ES Explorer, ale menedżer plików LG nie mógł wykryć typu pliku, więc moim rozwiązaniem jest
<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>
źródło
Content URI ftw i z filtrem intencji w manifeście ... jeśli Twoje pliki mają niestandardowe rozszerzenie .xyz, dodaj pasujący typ 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>
Niektóre aplikacje, takie jak poczta e-mail, wydają się konwertować rozszerzenie na typ MIME. Teraz mogę kliknąć załącznik w wiadomości e-mail i otworzyć go w mojej aplikacji.
źródło
Przeczytaj plik otwierający w kotlin:
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) } } }
źródło
Umieść ten filtr intencji wewnątrz tagu aktywności w manifeście, który chcesz otworzyć, dotykając pliku:
<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>
źródło
// Wypróbowałem ten kod. I to działa dobrze. Możesz użyć tego kodu, aby zaakceptować plik 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>
źródło