Androidインテントフィルター:アプリをファイル拡張子に関連付ける


92

アプリを関連付けたいカスタムファイルタイプ/拡張子があります。

私の知る限り、データ要素はこの目的のために作成されていますが、機能させることはできません。 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>

まあ、それは動作しません。何を間違えたのですか?自分のファイルタイプを宣言したいだけです。


インテントフィルターにandroid:label = "@ string / app_name"を追加
Prashant

回答:


116

処理するさまざまな状況に対処するには、複数のインテントフィルターが必要です。

例1、MIMEタイプなしでHTTPリクエストを処理する:

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

サフィックスが無関係である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: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>

host = "*"は省略できると思いましたが、範囲が広すぎました。
Phyrum Tea、2011

@Phyrum Tea:私のアプリを使用してファイル拡張子を他のアプリに関連付ける方法はありますか?私のアプリは.listファイルを生成します。これは、テキストファイルであることをandroidに伝え、テキストエディターで開くために必要です(私のアプリはテキストエディターではありません)。
Luis A. Florit 2013年

@ LuisA.Floritファイル* .txtを呼び出そうとしましたか?うまくいくかもしれません。
Gavriel、2015年

カスタム拡張がMimeTypeで機能しない。mimetypeを/に指定すると、Gmailの通知をクリックしたときにアプリが表示されます。
madan V 2015

1
動作していない..私は今、うんざりしているので、過去2日間から検索しても動作しませんでした。imはAndroid 9を使用
Ahmad Arslan

48

私が追加するまで、他の解決策は私にとって確実に機能しませんでした:

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
うわー!これは私を助けました。Androidのドキュメントが正しくないようです。すべて(scheme、host、path [Pattern]、mimeType)が機能するように宣言する必要があります
Gavriel

完全にしたい場合は、のあるルールとmimeTypeないルールの両方が必要です。developer.android.com/guide/components/…を
Andrew Sun

1
Gmailからファイルアプリを開きたい場合はどうなりますか?
IgorGanapolsky 2017年

30

Phyrum Teayukuによる回答は、すでに非常に有益です。

Android 7.0 Nougat以降、アプリ間のファイル共有の処理方法が変更されたことを追加します。

Android 7.0の公式の変更点

Android 7.0をターゲットとするアプリの場合、Androidフレームワークは、アプリの外部でfile:// URIを公開することを禁止するStrictMode APIポリシーを適用します。ファイルURIを含むインテントがアプリを離れると、アプリはFileUriExposedException例外で失敗します。

アプリケーション間でファイルを共有するには、content:// URIを送信し、URIに対する一時的なアクセス許可を付与する必要があります。このアクセス許可を付与する最も簡単な方法は、FileProviderクラスを使用することです。アクセス許可とファイルの共有の詳細については、「ファイルの共有」を参照してください。

独自のカスタムファイルを特定せずに終了している場合mime-type(または私も1と推測)あなたは、第二追加する必要があり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デバイスで私のアクティビティが開かないようにするこの小さな変更を見つけるのに苦労しました。誰かのお役に立てば幸いです。


このヒントと追加情報がないと、アプリをファイルエクスプローラーに登録できませんでした。これは重要であり、賛成する必要があります
u2tall

あなたは一日を節約しました!大きなtnx。これは受け入れられるべき答えです!
Andris

⚠️コンテンツスキーム経由で提供されたファイルを取得しようとすると、次のFile(uri.path)原因でクラッシュします。Nougat No such file or directory+をサポートするように更新する場合、そのシナリオを異なる方法で処理する必要があります。
ジョーダンH

19

私の発見:

ファイルを取得するさまざまな方法に対処するには、いくつかのフィルターが必要です。つまり、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:content://gmail-ls/l.foul@gmail.com/messages/2950/attachments/0.1/BEST/false:application / octet-stream:new。 mrz

ファイルエクスプローラーフィルター:

        <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>
  • ログ:ファイルインテントが検出されました:android.intent.action.VIEW:file:///storage/sdcard0/My%20Documents/new.mrz:null: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());
    }
}

アクティビティはランチャーまたはメインタイプである必要がありますか?Gmail添付ファイルフィルターを試してみましたが、機能しません。
2018年

15

pathPattern

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

ファイルパスに「.pdf」の前に1つ以上のドットが含まれている場合は機能しません。

これは動作します:

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

より多くのドットをサポートする場合は、さらに追加します。


1
現在のところ、これはサブフォルダに移動するための唯一のオプションです
LokiDroid

私は同じコードを使用していますが、IDEは私に警告を与え、この質問を見stackoverflow.com/questions/35833776/...
AndreaF

5

私はこれを長い間動作させるようにしており、提案されたすべての解決策を基本的に試しましたが、Androidに特定のファイル拡張子を認識させることができません。動作して"*/*"いるように見える唯一の方法であるMIME タイプのインテントフィルターがあり、ファイルブラウザーがファイルを開くためのオプションとして自分のアプリをリストするようになりましたが、私のアプリは今でもすべての種類のファイルを開くためのオプションとして表示されていますpathPatternタグを使用して特定のファイル拡張子を指定しました。これまでのところ、連絡先リストで連絡先を表示/編集しようとしても、Androidでアプリを使用して連絡先を表示するかどうかを尋ねられます。これは、これが発生する多くの状況の1つであり、非常に煩わしいものです。

ついに、このGoogleグループの投稿に、実際のAndroidフレームワークエンジニアが返信した同様の質問が見つかりました。彼女は、AndroidはMIMEタイプ(https://groups.google.com/forum/#!topic/android-developers/a7qsSl3vQq0)のみを認識し、ファイル拡張子については何も知らない、と説明しています。

したがって、私が見て、試し、読んだことから、Androidはファイル拡張子を区別できず、pathPatternタグは基本的に時間とエネルギーの巨大な無駄です。幸運なことに、特定のMIMEタイプ(テキスト、ビデオ、オーディオなど)のファイルのみが必要な場合は、MIMEタイプでインテントフィルターを使用できます。特定のファイル拡張子が必要な場合や、Androidで認識されていないMIMEタイプが必要な場合は、運が悪いです。

これについて私が間違っている場合は教えてください。これまでのところ、すべての投稿を読み、提案された解決策をすべて試しましたが、どれもうまくいきませんでした。

これらの種類のことがAndroidでどれほど一般的であり、開発者のエクスペリエンスが台無しになっているのかについて、別のページを1つまたは2つ書くことができますが、私はあなたの怒りの怒りを保存します;)私は誰かをいくつかのトラブルを救ったことを願っています。


5

Markus Resselは正しいです。Android 7.0 Nougatは、ファイルURIを使用したアプリ間のファイル共有を許可しなくなりました。コンテンツURIを使用する必要があります。ただし、コンテンツURIではMIMEタイプのみを共有できるため、ファイルパスを共有できません。したがって、コンテンツURIを使用してアプリを独自のファイル拡張子に関連付けることはできません。

DrobpoxはAndroid 7.0で興味深い動作をします。不明なファイル拡張子に遭遇すると、ファイルURIインテントを形成しているように見えますが、インテントを起動する代わりに、オペレーティングシステムを呼び出して、インテントを受け入れることができるアプリを見つけます。そのファイルURIを受け入れることができるアプリが1つしかない場合は、明示的なコンテンツURIをそのアプリに直接送信します。したがって、Dropboxを使用するために、アプリのインテントフィルターを変更する必要はありません。コンテンツURIインテントフィルターは必要ありません。アプリがコンテンツURIを受信できることと、独自のファイル拡張子を持つアプリがAndroid 7.0以前と同じようにDropboxで機能することを確認してください。

これは、コンテンツ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);
        ...
    }
}

1

追加してみてください

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

これで、application / pdfなどの工場設定のファイルタイプで機能するようになりましたが、独自のファイルタイプを宣言するにはどうすればよいですか?また、ファイルの種類とは、mimeTypeを意味します;)
Tamas

このMIMEタイプでどのようなファイルをキャッチしますか?また、このファイルはブラウザやファイルマネージャから開かれたり、作成した別のアプリケーションから送信されたりしますか?
magaio 2010

ブラウザー、メールクライアント、ファイルマネージャー、またはどこからでも可能です。または、独自のapp ofc :)ファイル拡張子はカスタムであり、クライアントによって指定されます。
タマス

ええと、私はまだ行き詰まっています...誰か助けてくれませんか?
Tamas

@タマスはあなたがこれをすべて並べ替えましたか?私はこれで立ち往生しています!
StuStirling 14

1

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++ / ... -->

必要な数のMIMEタイプを追加します。私のプロジェクトでのみ必要です。


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添付ファイルがアプリで開かれることに注意してください。これを回避する方法はありません。


これは、.teamz
IgorGanapolsky

1

@yukuと@ phyrum-teaが答えたように、他のFile Manager \ 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>

しかし、ESファイルエクスプローラーや他のファイルマネージャーでは機能しなかったため、追加しました

 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>

1

コンテンツ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タイプに変換するようです。これで、メールの添付ファイルをクリックして、アプリで開くことができます。


1

これを試してみると、PDFの代わりに他の拡張機能も使用できます。まず、androidmanifest.xmlファイルに外部ストレージの読み取り権限を追加する必要があります。

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

次に、Activityタグのandroidmanifestファイルに、以下に示すようにインテントフィルターを追加します。

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

        }

このIntent.ACTION_VIEWの場合、ファイルパスを取得できないため、エラーが発生します:java.io.FileNotFoundException:権限が拒否されました。常にではなく、一部の特定のアプリケーションからのみです。解決策はありますか?
Hardik Joshi

@HardikJoshiアプリが権限GRANT_READ_URI_PERMISSIONを設定していない可能性があります。
Mira_Cole

1

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) 
        }
    }
}

-1

このインテントフィルターを、ファイルを開いて開きたいマニフェストのアクティビティタグ内に配置します。

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

-1

//このコードを試しました。そして、それはうまく機能しています。このコードを使用して、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>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.