Android Intent Filter für eine bestimmte Dateierweiterung?

92

Ich möchte in der Lage sein, eine Datei mit einer bestimmten Erweiterung aus dem Internet herunterzuladen und sie an meine Anwendung weiterzuleiten, um damit umzugehen, aber ich konnte den Absichtsfilter nicht herausfinden. Der Dateityp ist nicht in den Mimetypen enthalten, und ich habe versucht, ihn zu verwenden

<data android:path="*.ext" />

aber ich konnte das nicht zum Laufen bringen.

Curyous
quelle

Antworten:

119

Hier ist, wie ich meine Aktivität in meiner AndroidManifest.xml definiert habe, damit dies funktioniert.

<activity android:name="com.keepassdroid.PasswordActivity">
    <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:mimeType="*/*" />
        <data android:pathPattern=".*\\.kdb" />
        <data android:host="*" />
    </intent-filter>
</activity>

Das schemevon filegibt an, dass dies passieren soll, wenn eine lokale Datei geöffnet wird (anstelle eines Protokolls wie HTTP).

mimeTypekann so eingestellt werden, dass sie \*/\*zu jedem MIME-Typ passt.

pathPatternHier geben Sie an, mit welcher Erweiterung Sie übereinstimmen möchten (in diesem Beispiel .kdb). Das .*am Anfang entspricht einer beliebigen Anzahl von Zeichen. Diese Zeichenfolgen müssen doppelt maskiert werden, entsprechen also \\\\.einer wörtlichen Periode. Dann beenden Sie mit Ihrer Dateierweiterung. Eine Einschränkung bei pathPattern ist, dass .*es sich nicht um eine gierige Übereinstimmung handelt, wie Sie es erwarten würden, wenn dies ein regulärer Ausdruck wäre. Dieses Muster stimmt nicht mit Pfaden überein, die ein .vor dem enthalten .kdb. Eine ausführlichere Beschreibung dieses Problems und eine Problemumgehung finden Sie hier

Gemäß der Android-Dokumentation sind schließlich sowohl hostals auch schemeAttribute erforderlich, damit das pathPatternAttribut funktioniert. Setzen Sie dies also einfach auf den Platzhalter, damit alles übereinstimmt.

Wenn Sie nun eine .kdbDatei in einer App wie Linda File Manager auswählen , wird meine App als Option angezeigt. Ich sollte beachten, dass dies allein nicht das Herunterladen dieses Dateityps in einem Browser ermöglicht, da dies nur beim Dateischema registriert wird. Wenn Sie eine App wie Linda File Manager auf Ihrem Telefon haben, können Sie jeden Dateityp generisch herunterladen.

Brian Pellin
quelle
3
Das funktioniert hier nicht. Zuerst mit mimeType = " ", das Paket wird nicht auf Android 2.1 installiert, ich bekomme eine MalformedMimeTypeException. Die Verwendung von "* / " behebt dies, aber dieser Filter hat keine Auswirkung. Ich teste derzeit mit dem Skyfire-Browser, der den MIME-Typ von Downloads nicht wie der Standard-Android-Browser beibehält. Wenn Sie auf eine Datei in der Skyfire-Downloadliste klicken, wird eine vereinfachte VIEW-Absicht mit Dateidaten gesendet. Und dieser Absichtsfilter stimmt nicht überein.
Olivierg
@Brian Pellin: Ich habe tatsächlich nach einer Möglichkeit gesucht, einen MIME-Typ an die .kdbxErweiterung zu binden , damit der ES-Datei-Explorer kdbx-Dateien öffnen kann, als ich auf diesen Beitrag verwiesen wurde. Anscheinend funktioniert dieser Absichtsfilter nicht, wenn die Absicht einen leeren MIME-Typ hat !! Es ist auch möglich, eine Absicht mit einer LEEREN Zeichenfolge als Aktion und nur einer URI zu haben. Google Text & Tabellen hat auf diese Absicht reagiert, daher muss sie gültig sein.
billc.cn
2
Um ganz klar zu sein, mimeType sollte "* / *" sein. Ich denke, einige Leute haben vergessen, ihren * s zu entkommen
Brian Pellin
1
Das funktioniert nicht mit Android 4. Sie sollten ein <data>Tag mit vier Attributen verwenden. 4 Tags zu haben ist logisch ODER - was mit Android 2 funktioniert hat - aber Android 4 ist strenger. Siehe stackoverflow.com/questions/20650378/…
Martin
3
Wenn \\\\.eine Literalperiode übereinstimmt, warum verwenden Sie sie nicht, um eine .kdbErweiterung wie diese zu bilden : \\\\.kdb?
Lealo
32

Es gibt viele Fehlinformationen zu diesem Thema, nicht zuletzt aus Googles eigener Dokumentation. Die beste und angesichts der seltsamen Logik möglicherweise einzige Quelldokumentation ist der Quellcode.

Die Absichtsfilterimplementierung hat eine Logik, die sich fast jeder Beschreibung entzieht. Der Parser-Code ist das andere relevante Puzzleteil.

Die folgenden Filter kommen einem vernünftigen Verhalten ziemlich nahe. Die Pfadmuster gelten für "Datei" -Schemaabsichten.

Die globale Übereinstimmung des MIME-Typmusters stimmt mit allen Typen überein, solange die Dateierweiterung übereinstimmt. Dies ist nicht perfekt, aber die einzige Möglichkeit, das Verhalten von Dateimanagern wie ES File Explorer anzupassen, und es ist auf Absichten beschränkt, bei denen die URI / Dateierweiterung übereinstimmt.

Ich habe hier keine anderen Schemata wie "http" aufgenommen, aber sie werden wahrscheinlich bei all diesen Filtern gut funktionieren.

Das ungerade Schema ist "Inhalt", für den die Erweiterung dem Filter nicht zur Verfügung steht. Solange der Anbieter Ihren MIME-Typ angibt (z. B. gibt Google Mail den MIME-Typ für den Anhang ungehindert weiter), stimmt der Filter überein.

Zu beachtende Fallstricke:

  1. Beachten Sie, dass sich in den Filtern nichts konsistent verhält, es ist ein Labyrinth von Sonderfällen und behandelt Verstöße gegen das Prinzip der geringsten Überraschung als Entwurfsziel. Keiner der Mustervergleichsalgorithmen folgt der gleichen Syntax oder dem gleichen Verhalten. Das Fehlen eines Feldes ist manchmal ein Platzhalter und manchmal nicht. Attribute innerhalb eines Datenelements müssen manchmal zusammenpassen und manchmal die Gruppierung ignorieren. Es hätte wirklich besser gemacht werden können.
  2. Das Schema UND der Host müssen angegeben werden, damit die Pfadregeln übereinstimmen (im Gegensatz zum aktuellen API-Handbuch von Google).
  3. Zumindest ES File Explorer generiert Absichten mit einem MIME-Typ von "", der sehr unterschiedlich nach null gefiltert wird, nicht explizit übereinstimmt und nur vom riskanten "* / *" - Filter abgeglichen werden kann.
  4. Der Filter "* / *" stimmt NICHT mit Absichten mit einem Null-MIME-Typ überein. Für diesen speziellen Fall ist ein separater Filter ohne MIME-Typ erforderlich.
  5. Das Schema "Inhalt" kann nur nach MIME-Typ abgeglichen werden, da der ursprüngliche Dateiname in der Absicht nicht verfügbar ist (zumindest bei Google Mail).
  6. Die Gruppierung von Attributen in separaten "Daten" -Elementen ist für die Interpretation (fast) irrelevant, mit Ausnahme von Host und Port, die sich paaren. Alles andere hat keine spezifische Zuordnung innerhalb eines "Daten" -Elements oder zwischen "Daten" -Elementen.

In diesem Sinne hier ein Beispiel mit Kommentaren:

<!--
     Capture content by MIME type, which is how Gmail broadcasts
     attachment open requests.  pathPattern and file extensions
     are ignored, so the MIME type *MUST* be explicit, otherwise
     we will match absolutely every file opened.
-->
<intent-filter
    android:icon="@drawable/icon"
    android:label="@string/app_name"
    android:priority="50" >
    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.BROWSABLE" />
    <category android:name="android.intent.category.DEFAULT" />

    <data android:scheme="file" />
    <data android:scheme="content" />
    <data android:mimeType="application/vnd.my-type" />
</intent-filter>

<!--
     Capture file open requests (pathPattern is honoured) where no
     MIME type is provided in the Intent.  An Intent with a null
     MIME type will never be matched by a filter with a set MIME
     type, so we need a second intent-filter if we wish to also
     match files with this extension and a non-null MIME type
     (even if it is non-null but zero length).
-->
<intent-filter
    android:icon="@drawable/icon"
    android:label="@string/app_name"
    android:priority="50" >
    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.BROWSABLE" />
    <category android:name="android.intent.category.DEFAULT" />

    <data android:scheme="file" />
    <data android:host="*" />

    <!--
         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:pathPattern=".*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.my-ext" />
</intent-filter>

<!--
     Capture file open requests (pathPattern is honoured) where a
     (possibly blank) MIME type is provided in the Intent.  This
     filter may only be necessary for supporting ES File Explorer,
     which has the probably buggy behaviour of using an Intent
     with a MIME type that is set but zero-length.  It's
     impossible to match such a type except by using a global
     wildcard.
-->
<intent-filter
    android:icon="@drawable/icon"
    android:label="@string/app_name"
    android:priority="50" >
    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.BROWSABLE" />
    <category android:name="android.intent.category.DEFAULT" />

    <data android:scheme="file" />
    <data android:host="*" />
    <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:pathPattern=".*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\.my-ext" />
    <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\..*\\..*\\.my-ext" />
</intent-filter>
David Sainty
quelle
Schön, dass Sie dem vielen nachgewiesenen Bedürfnis nach \\ .. immer und immer wieder und anderen Macken standhalten. Google hätte dies um 4.2 beheben sollen, was zur Hölle. Leider habe ich immer noch Fälle, die Ihr Beispiel nicht zu beheben scheint. Gibt es ein Problem mit 6 Cha-Erweiterungen wie ".gblorb", dass mein Code mit 3 Buchstaben oder weniger gut funktioniert?
RoundSparrow Hilltx
Beste Antwort auf diese Frage und ähnliche Fragen meiner Meinung nach! Solange es nicht möglich ist, Inhaltsabsichten nach Dateierweiterung abzugleichen (wie Sie in 5. darauf hinweisen), ist es leider nicht möglich, zuverlässig nach ALLEN korrekten Absichten zu filtern, ohne auch falsche abzugleichen. Dies ist der Fall, wenn Sie keinen benutzerdefinierten MIME-Typ verwenden können. Solange Android keine Lösung dafür bietet, wird es für mich eine Dateiauswahl innerhalb der App sein ... Ich möchte den Benutzer nicht mit inkonsistentem Verhalten verwechseln.
Benjamin Bisinger
1
Vielen Dank. Sie haben gerade meinen Tag gemacht. In meinem Fall musste ich MimeType wie <data android:mimeType="*/*" /> in allen drei Optionen ändern und es funktionierte wie ein Zauber für alle Apps, einschließlich Google Drive und Google Mail.
Rishabh Wadhwa
1
Ich möchte mich so sehr bei Ihnen bedanken, @David Sainty. Sie beenden meine 24-Stunden-Qual, herauszufinden, wie ich damit umgehen soll. Ich habe versucht, stackoverflow.com/q/18577860/6110285 , stackoverflow.com/a/8599921/6110285 und viele andere, die ähnlich waren. Dieser ist der einzige, der funktioniert hat.
Pittix
24

Ich muss zugeben, dass die einfache Aufgabe, Anhänge aus E-Mails und Dateien aus dem Dateisystem auf Android zu öffnen, eine der verrücktesten Erfahrungen war, die es je gab. Es ist einfach, mit zu vielen oder zu wenigen Dateien umzugehen. Aber es ist schwer, es genau richtig zu machen. Die meisten auf stackoverflow veröffentlichten Lösungen funktionierten bei mir nicht richtig.

Meine Anforderungen waren:

  • Lassen Sie meine App Anhänge verarbeiten, die von meiner App freigegeben wurden
  • Lassen Sie meine App Dateien im Dateispeicher verarbeiten, die von meiner App generiert wurden und eine bestimmte Erweiterung haben

Der wahrscheinlich beste Weg, um diese Aufgabe zu erledigen, besteht darin, einen benutzerdefinierten MIME-Typ für Ihre Anhänge anzugeben. Und Sie werden sich wahrscheinlich auch für eine benutzerdefinierte Dateierweiterung entscheiden. Nehmen wir also an, unsere App heißt "Cool App" und wir generieren Dateianhänge mit ".cool" am Ende.

Dies ist der Punkt, an dem ich meinem Ziel am nächsten gekommen bin und der funktioniert ... zufriedenstellend.

<!-- Register to handle email attachments -->
<!-- WARNING: Do NOT use android:host="*" for these as they will not work properly -->
<intent-filter>
    <!-- needed for properly formatted email messages -->
    <data
        android:scheme="content"
        android:mimeType="application/vnd.coolapp"
        android:pathPattern=".*\\.cool" />
    <!-- needed for mangled email messages -->
    <data
        android:scheme="content"
        android:mimeType="application/coolapp"
        android:pathPattern=".*\\.cool" />
    <!-- needed for mangled email messages -->
    <data
        android:scheme="content"
        android:mimeType="application/octet-stream"
        android:pathPattern=".*\\.cool" />

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

    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
</intent-filter>

<!-- Register to handle file opening -->
<intent-filter>
    <data android:scheme="file"
          android:mimeType="*/*"
          android:pathPattern=".*\\.cool"
          android:host="*"/>

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

    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
</intent-filter>

Anmerkungen:

  • Das pathPatternscheint für Anhänge (bei Verwendung android:scheme="content") mehr oder weniger ignoriert zu werden . Wenn jemand das pathPattern dazu bringt, nur auf bestimmte Muster zu reagieren, würde ich mich freuen zu sehen, wie.
  • Die Google Mail-App hat sich geweigert, meine App in der Auswahl aufzulisten, wenn ich das android:host="*"Attribut hinzugefügt habe .
  • Es funktioniert wahrscheinlich immer noch, wenn diese intent-filterBlöcke zusammengeführt werden, aber ich habe dies nicht überprüft.
  • Um Anfragen von einem Browser beim Herunterladen einer Datei zu bearbeiten, android:scheme="http"kann die verwendet werden. Beachten Sie, dass bestimmte Browser das android:mimeTypeExperimentieren durcheinander bringen android:mimeType="*/*"und im Debugger überprüfen können, was tatsächlich durchlaufen wird, und dann die Filterung verschärfen, um nicht die nervige App zu werden, die alles handhabt .
  • Bestimmte File Explorer werden auch die MIME-Typen für Ihre Dateien durcheinander bringen. Das Obige intent-filterwurde mit der Samsung-App "My Files" auf einem Galaxy S3 getestet. Der FX Explorer weigert sich immer noch, die Datei ordnungsgemäß zu öffnen, und ich habe auch festgestellt, dass das App-Symbol nicht für die Dateien verwendet wird. Wenn jemand das zum Laufen bringt, kommentieren Sie bitte unten.

Ich hoffe, Sie finden dies nützlich und müssen keine Tage damit verschwenden, alle möglichen Kombinationen durchzugehen. Es gibt Raum für Verbesserungen, daher sind Kommentare willkommen.

Omahena
quelle
Dies ist eine funktionierende Lösung für mich. Das Registrieren eines separaten <intent-filters> für Content-Scheme und File-Scheme hat den Trick getan! Vielen Dank!
Mehlyfication
Vielen Dank! Hat für mich gearbeitet. Sowohl die Google Mail-App als auch die Samsung My Files-App auf dem Galaxy S6 konnten mit Ihrer Lösung Dateien mit meiner App öffnen!
Haris
Was genau ist der "App-Name"? (In meinem Fall enthält der für Menschen lesbare App-Name Leerzeichen.)
William Jockusch
@WilliamJockusch Es sieht so aus, als würde @DavidSainty einfach den Anwendungsnamen in der String-Ressourcendatei speichern. Leerzeichen sollten in Ordnung sein. Die Zeichenfolge, die android:labelfür den Intent-Filter verwendet wird, ist die Zeichenfolge, die der Benutzer im Auswahlmenü sieht. Standardmäßig wird der Anwendungsname verwendet.
Omahena
Was soll ich für die App "Google Drive" verwenden?
Android-Entwickler
9

Brians Antwort hat mich zu 90% dorthin gebracht. Zum Abschluss habe ich für MIME-Typ verwendet

android:mimeType="*/*"

Ich vermute, dass frühere Poster versucht haben, das gleiche Detail zu veröffentlichen, aber wenn der Stern-Schrägstrich-Stern nicht als Code angegeben wird, wird er durch den Stapelüberlauf nur als Schrägstrich dargestellt.

Dawson
quelle
2
Damit werden Sie ALLE Dateitypen behandeln, und das ist wirklich ärgerlich (
Tim Autin
Das ist schlecht. Bitte tun Sie dies nicht in Ihren Apps.
Mars
8

Anstatt android:path, versuchen Sie android:mimeType, mit einem Wert des MIME - Typ dieser bestimmten Inhalt. Auch android:pathakzeptiert keine Platzhalter - Verwendung android:pathPatterndafür.

CommonsWare
quelle
"Der Dateityp ist nicht in den Mimetypen enthalten"? Es sollte immer noch einen Mimetyp für die Art des Inhalts geben, den Sie herunterladen, auch wenn nicht dasselbe Wort verwendet wird.
Eric Mill
Es gibt einen Mimetyp für den Inhaltstyp, aber die Datei wird von einer Drittanbieteranwendung erstellt, die eine andere Erweiterung verwendet, sodass ich nicht glaube, dass sie als dieser Mimetyp erkannt wird.
Curyous
7

Ich habe seit Ewigkeiten versucht, dies zum Laufen zu bringen, habe im Grunde alle vorgeschlagenen Lösungen ausprobiert und kann Android immer noch nicht dazu bringen, bestimmte Dateierweiterungen zu erkennen. Ich habe einen Intent-Filter mit einem"*/*" Mimetyp, der das einzige ist, was zu funktionieren scheint, und Dateibrowser listen meine App jetzt als Option zum Öffnen von Dateien auf. Meine App wird jetzt jedoch als Option zum Öffnen einer beliebigen Art von Datei angezeigt, obwohl Ich habe mithilfe des pathPattern-Tags bestimmte Dateierweiterungen angegeben. Dies geht so weit, dass Android mich fragt, ob ich meine App zum Anzeigen des Kontakts verwenden möchte, selbst wenn ich versuche, einen Kontakt in meiner Kontaktliste anzuzeigen / zu bearbeiten. Dies ist nur eine von vielen Situationen, in denen dies auftritt, SEHR SEHR ärgerlich.

Schließlich fand ich diesen Google-Gruppenbeitrag mit einer ähnlichen Frage, auf die ein tatsächlicher Android-Framework-Ingenieur antwortete. Sie erklärt, dass Android einfach nichts über Dateierweiterungen weiß, sondern nur MIME-Typen ( https://groups.google.com/forum/#!topic/android-developers/a7qsSl3vQq0 ).

Nach dem, was ich gesehen, ausprobiert und gelesen habe, kann Android einfach nicht zwischen Dateierweiterungen unterscheiden, und das pathPattern-Tag ist im Grunde eine gigantische Zeit- und Energieverschwendung. Wenn Sie das Glück haben, nur Dateien eines bestimmten MIME-Typs (z. B. Text, Video oder Audio) zu benötigen, können Sie einen Intent-Filter mit einem MIME-Typ verwenden. Wenn Sie jedoch eine bestimmte Dateierweiterung oder einen MIME-Typ benötigen, den Android nicht kennt, haben Sie kein Glück.

Wenn ich mich in irgendetwas irre, sag es mir bitte. Bisher habe ich jeden Beitrag gelesen und jede vorgeschlagene Lösung ausprobiert, die ich finden konnte, aber keine hat funktioniert.

Ich könnte noch ein oder zwei Seiten darüber schreiben, wie häufig solche Dinge in Android zu sein scheinen und wie durcheinander die Entwicklererfahrung ist, aber ich werde Ihnen meine wütenden Beschimpfungen ersparen;). Hoffe, ich habe jemandem Ärger erspart.

PeeGee85
quelle
1
Sie wurden positiv bewertet, weil Ihre Antwort einen nützlichen Link enthält und der Downvoter keinen Kommentar hinterlassen hat. Tut mir leid, SO kann manchmal so unfreundlich sein, aber hör nicht damit auf.
John Hatton
3

Brians Antwort ist sehr nah, aber hier ist eine saubere und fehlerfreie Möglichkeit, Ihre App aufzurufen, wenn Sie versuchen, eine Datei mit Ihrer eigenen benutzerdefinierten Erweiterung zu öffnen (kein Schema oder Host erforderlich):

<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:mimeType="*/*" />
    <data android:pathPattern="*.*\\.kdb" />
</intent-filter>
Kon
quelle
2
In der Android-Dokumentation heißt es, dass das pathPattern-Attribut nur dann von Bedeutung ist, wenn ein Schema und ein Host angegeben sind, und ich habe dies überprüft: developer.android.com/guide/topics/manifest/data-element.html
Brian Pellin
4
-1; Dies passt zu jeder Datei. Brians Kommentar ist korrekt und mit der geringfügigen Änderung von mimeType = " / " ist sein ursprüngliches Beispiel perfekt.
Nick
Dieser Beitrag stammt von vor langer Zeit, aber kein "/" wird nicht installiert. Sie benötigen "* / *", das jedem Dateityp entspricht (nicht sicher, ob Sie dies sagen wollten). Daher wird Ihr Programm möglicherweise aufgefordert, Videos oder MP3s zu öffnen. Ich habe noch keine Lösung dafür gefunden.
Rene
Sie sollten ein <data>Tag mit vier Attributen verwenden. Ihre Lösung funktioniert möglicherweise mit Android 2 - aber die Regeln sind strenger geworden: stackoverflow.com/questions/20650378/…
Martin
Was ist mit dem seltsamen pathPattern los ? Und hostund schemesind erforderlich!
IgorGanapolsky
3

Unter Android 4 wurden die Regeln strenger als früher. Verwenden:

    <data
      android:host=""
      android:mimeType="*/*"
      android:pathPattern=".*\\.ext"
      android:scheme="file"
    ></data>
Martin
quelle
3

Ich habe selbst ziemlich viel damit zu kämpfen, um eine benutzerdefinierte Dateierweiterung zu erhalten. Nach langem Suchen habe ich diese Webseite gefunden, auf der das Poster feststellte, dass die patternMatcher-Klasse von Android (die für den pathPattern-Abgleich in Absichtsfiltern verwendet wird) ein unerwartetes Verhalten aufweist, wenn Ihr Pfad das erste Zeichen Ihres Übereinstimmungsmusters an einer anderen Stelle im Pfad enthält (Wenn Sie beispielsweise versuchen, mit "* .xyz" übereinzustimmen, wird die patternMatcher-Klasse gestoppt, wenn sich früher in Ihrem Pfad ein "x" befindet.) Folgendes hat er für eine Problemumgehung gefunden und für mich gearbeitet, obwohl es ein bisschen hackt:

PatternMatcher wird bei intentFilter für pathPattern verwendet. Der Algorithmus von PatternMatcher ist mir jedoch ziemlich fremd. Hier ist der Algorithmus von Android PatternMatcher.

Wenn sich in der Mitte des Strings das 'nächste Zeichen' des Musters '. *' Befindet, stoppt PatternMatcher die Schleife an diesem Punkt. (Siehe PatternMatcher.java des Android-Frameworks.)

Ex. Zeichenfolge: "Dies ist mein Anhang" Muster: ". att. ". Android PatternMatcher Geben Sie die entsprechende Schleife ein. 'Muster bis zum nächsten Zeichen des Musters (in diesem Beispiel' a ') Also,'. 'Matching Loop stoppt bei Index 8 -' a 'zwischen' is 'und' my '. Daher gibt das Ergebnis dieser Übereinstimmung 'false' zurück.

Ziemlich seltsam, nicht wahr? Um dies zu umgehen - tatsächlich die Möglichkeit zu reduzieren - sollte der Entwickler nerviges dummes pathPattern verwenden.

Ex. Ziel: Übereinstimmender Uri-Pfad, der 'Nachricht' enthält.

<intent-filter>
...
<data android:pathPattern=".*message.*" />
<data android:pathPattern=".*m.*message.*" />
<data android:pathPattern=".*m.*m.*message.*" />
<data android:pathPattern=".*m.*m.*m.*message.*" />
<data android:pathPattern=".*m.*m.*m.*m.*message.*" />
...
</intent-filter>

Dies wird insbesondere beim Abgleich mit der benutzerdefinierten Dateierweiterung ausgegeben.

benjamin davis
quelle
Für alle Interessierten wurde ein Problem
benjamin davis am
3

Keine der oben genannten Funktionen funktioniert ordnungsgemäß für VIEW- oder SEND-Aktionen, wenn das Suffix nicht mit einem MIME-Typ in der system = wide MIME-Datenbank von Android registriert ist. Die einzigen Einstellungen, die ich gefunden habe, sind das Auslösen für das angegebene Suffix android:mimeType="*/*", aber dann wird die Aktion für ALLE Dateien ausgelöst. Ganz klar NICHT was du willst!

Ich kann keine richtige Lösung finden, ohne die MIME und das Suffix zur Android-MIME-Datenbank hinzuzufügen. Bisher habe ich keinen Weg gefunden, dies zu tun. Wenn jemand weiß, wäre ein Zeiger großartig.

Glenn Widener
quelle
2

Wenn eine Absicht a erfüllt intent-filter, sind dies die intent-filterAnforderungen: (Stellen Sie sich eine Checkliste vor).

  • Jede Übereinstimmung <action>
  • Jede Übereinstimmung <category>
  • Beliebiges Matching <data mimeType>(einfache Lösung: " / ")
  • Optional:

    • Jede passende <data scheme>(einfache Lösung: <data android:scheme="file" /> <data android:scheme="content" />)

    • Beliebige Übereinstimmungen <data host>(einfache Lösung: "*")

    • Jede Übereinstimmung <data pathPattern/etc.>(zum Beispiel .*\\.0cc)

Durch das Definieren mehrerer <data $type="">Elemente wird das Kontrollkästchen $ type aktiviert, wenn eines mit dem <data $type=>übereinstimmt Intent.

Das Weglassen von mimeType unterbricht Ihre intent-filter, obwohl es scheinbar überflüssig ist. Durch das Weglassen stimmt <data scheme/host/pathPattern>Ihr Filter mit allem überein.

https://f-droid.org/en/packages/de.k3b.android.intentintercept/ ist eine App, die alle Absichten empfängt und es Ihnen ermöglicht, die Absicht zu überprüfen. Ich habe erfahren, dass nicht erkannte Dateierweiterungen, die über den Simple File Manager geöffnet wurden, vom Typ MIME geliefert werden application/octet-stream.

https://stackoverflow.com/a/4621284/2683842 meldet, dass der <data pathPattern=> .*xyzVorgang beim ersten Mal abgebrochen xwird und sofort fehlschlägt, wenn nicht gefolgt wird yz. So /sdcard/.hidden/foo.0ccwird nicht passieren , .*\\.0ccwenn Sie versuchen , .*\\..*\\.0ccstatt.

  • Ich habe nicht überprüft, ob diese Problemumgehung erforderlich ist.

Endresultat:

<activity android:name=".Ft2NsfActivity">

    <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:host="*" />
        <data android:pathPattern=".*\\.ftm"/>
        <data android:pathPattern=".*\\..*\\.ftm"/>
        <data android:pathPattern=".*\\..*\\..*\\.ftm"/>
        <data android:pathPattern=".*\\..*\\..*\\..*\\.ftm"/>
        <data android:pathPattern=".*\\.0cc"/>
        <data android:pathPattern=".*\\..*\\.0cc"/>
        <data android:pathPattern=".*\\..*\\..*\\.0cc"/>
        <data android:pathPattern=".*\\..*\\..*\\..*\\.0cc"/>
        <data android:mimeType="*/*" />
    </intent-filter>

</activity>
nyanpasu64
quelle
1

Wenn Sie möchten, dass die Dateien direkt über Google Mail, Dropbox oder eines der integrierten Android-Datei-Tools geöffnet werden, verwenden Sie den folgenden Code (löschen Sie 'android: host = "*"', wodurch die Datei für Google Mail nicht erreichbar war):

<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="content" android:pathPattern=".*\\.kdb" 
          android:mimeType="application/octet-stream"/>


</intent-filter>

<intent-filter>
    <action android:name="android.intent.action.VIEW"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:scheme="file" android:mimeType="*/*"     
          android:pathPattern=".*\\.kdb"/>
</intent-filter>

Der Datenfilter muss gemäß Android Version 4.x in einer Anweisung geschrieben sein

AndreasReiff
quelle
Ich habe alles versucht, um das Herunterladen und Öffnen des Android-Browsers zum Funktionieren zu bringen. Ihre Lösung funktioniert gut für Android native Browser und Android Chrome, aber Android Firefox scheint meine Datei immer noch in einem Textfenster zu öffnen. Es ist ein benutzerdefinierter MIME-Typ und eine benutzerdefinierte Erweiterung. Bisher funktionierte es nur mit der Erweiterung nur in Firefox. Jetzt funktioniert es überall außer Firefox (einschließlich Google Mail). Ich teste es immer noch, aber ich wollte nur darauf hinweisen, dass es hier eine Reihe neuer browserübergreifender Probleme gibt.
Damon Smith
1

Verwenden Sie den Filter wie folgt, um ihn über Browser, Google Mail und den Dateibrowser zu öffnen (getestet). HINWEIS: Bitte führen Sie nicht zwei Filter zusammen, damit der Browser Ihre App ignoriert (getestet).

        <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" android:pathPattern=".*\\.ext" android:mimeType="application/*"/>
            <data android:scheme="content" android:pathPattern=".*\\.ext" android:mimeType="application/*"/>
        </intent-filter>

        <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="http"
                  android:host="*"
                  android:pathPattern=".*\\.ext" />
            <data android:scheme="https"
                  android:host="*"
                  android:pathPattern=".*\\.ext" />
            <data android:scheme="ftp"
                  android:host="*"
                  android:pathPattern=".*\\.ext" />

        </intent-filter>
Tran Hieu
quelle
Haben Sie diese Antwort mit Google Mail-Anhängen getestet?
IgorGanapolsky
1

Update 2020

Android hat sich in Richtung Inhalts-URIs und MIME-Typen für Absichtsfilter bewegt.

Das Problem

Eine Inhalts-URI muss nicht unbedingt die Erweiterung oder den Namen der Datei enthalten und unterscheidet sich zwischen verschiedenen Anwendungen, die den Inhalt / die Datei bereitstellen.

Hier einige Beispiele für Inhalts-URIs aus verschiedenen E-Mail-Anwendungen für denselben E-Mail-Anhang:

Google Mail -> content://com.google.android.gm.sapi/[email protected]/message_attachment_external/%23thread-a%3Ar332738858767305663/%23msg-a%3Ar-5439466788231005876/0.1?account_type=com.google&mimeType=application%2Foctet-stream&rendition=1

Ausblick -> content://com.microsoft.office.outlook.fileprovider/outlookfile/data/data/com.microsoft.office.outlook/cache/file-download/file--2146063402/filename.customextention

Samsung Email App -> content://com.samsung.android.email.attachmentprovider/1/1/RAW

Wie Sie sehen können, sind sie alle unterschiedlich und enthalten garantiert nichts, was mit Ihrer tatsächlichen Datei zusammenhängt. Daher können Sie nicht das verwenden, was die android:pathPatternmeisten vorgeschlagen haben.

Eine Workaround-Lösung für E-Mail-Anhänge

<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="content"/>
    <data android:host="*"/>

    <!--  Required for Gmail and Samsung Email App  -->
    <data android:mimeType="application/octet-stream"/>

    <!--  Required for Outlook  -->
    <data android:mimeType="application/my-custom-extension"/>
</intent-filter>

Durch Tests habe ich die von Google Mail, Outlook und Samsung Email verwendeten MIME-Typen gefunden und diese meinem Intent-Filter hinzugefügt.

Vorsichtsmaßnahmen / Fallstricke

  • Ich habe festgestellt, dass mit meiner obigen Lösung beim Öffnen einer Binärdatei automatisch meine App gestartet wird. Ich habe dies in meiner Aktivität behandelt, indem ich einen fehlgeschlagenen Status angezeigt habe, wenn wir die Datei nicht analysieren konnten. Ich dachte, dies sei ein ziemlich seltenes Ereignis, also wäre es akzeptabel.

  • Ich konnte keine Möglichkeit finden, meine App über den Dateibrowser zu starten, ohne <data android:mimeType="*/*"/>meinen Intent-Filter zu erweitern. Ich konnte dies nicht verwenden, da meine App dann immer dann gestartet wurde, wenn der Benutzer auf eine Datei auf seinem Telefon klickte (nicht nur auf die Dateien mit der benutzerdefinierten Dateierweiterung). Ich würde nicht empfehlen, dies Ihrem Intent-Filter hinzuzufügen.

Abschließende Gedanken

  • Derzeit gibt es keine elegante Lösung, um Ihre App einem bestimmten Erweiterungstyp in Android zuzuordnen. Dies war das Beste, was ich in meiner Situation tun konnte.
Alexander Antaya
quelle