web-dev-qa-db-ja.com

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>

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

90
Tamas

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

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

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>
113
Phyrum Tea

私が追加するまで、他のソリューションは私にとって確実に機能しませんでした:

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

Phyrum Tea および yuk で与えられる答えは、すでに非常に有益です。

Android 7.0 Nougatで始まることを追加したいと思います。アプリ間のファイル共有の処理方法に変更があります。

公式から Android 7.0の変更

Android 7.0を対象とするアプリの場合、Androidフレームワークは、アプリの外部でfile:// URIを公開することを禁止するStrictMode APIポリシーを実施します。 URIがアプリを離れると、アプリはFileUriExposedException例外で失敗します。

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

特定のmime-typeなしで終了する独自のカスタムファイルがある場合(または1つでも推測される場合)、2番目の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デバイスで開くことができませんでした。

22
Markus Ressel

私の発見:

ファイルを取得するさまざまな方法に対処するには、いくつかのフィルターが必要です。つまり、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/[email protected]/messages/2950/attachments/0.1/BEST/false:application/octet-stream:新規。 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());
    }
}
19
LFOR

pathPattern

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

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

これは動作します:

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

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

15

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。

コンテンツ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);
        ...
    }
}
4
Peter Newman

私はこれを長年にわたって機能させようとしてきましたが、基本的にすべての提案された解決策を試してみましたが、Androidを取得して特定のファイル拡張子を認識できません。 "*/*" mimetypeを持つインテントフィルターがあり、これが機能しているように見える唯一のものであり、ファイルブラウザーはファイルを開くためのオプションとしてアプリを一覧表示しますが、現在、アプリはANYを開くためのオプションとして表示されていますpathPatternタグを使用して特定のファイル拡張子を指定したにもかかわらず、ファイルの種類。連絡先リストで連絡先を表示/編集しようとしても、Androidから連絡先を表示するためにアプリを使用するかどうかを尋ねられますが、これは多くの状況の1つです発生し、非常に非常に迷惑です。

最終的に、実際のAndroidフレームワークエンジニアが答えた同様の質問でこのGoogleグループの投稿を見つけました。彼女はAndroidは単にファイル拡張子について何も知らず、MIMEタイプのみを知っていると説明しています( https://groups.google.com/forum/#!topic/Android-developers/a7qsSl3vQq )。

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

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

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

3
PeeGee85

追加してみてください

<action Android:name="Android.intent.action.VIEW"/>
2
magaio

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

コンテンツ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

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
Hrk
         <!--
            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ファイルの添付ファイルを開くようになります。回避策はありません。

1
Ofir Bitton

これを試してみてください。pdfの代わりに他の拡張機能も使用できます。最初に、外部ストレージの読み取り許可をandroidmanifest.xmlファイルに追加する必要があります。

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

次に、Activityタグのandroidmanifestファイルで、以下に示すようにintent-filterを追加します。

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

        }
1
Arjun Othayoth

//このコードを試しました。そして、それはうまく機能しています。このコードを使用して、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>
0
Arslan Tahir

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