[android] 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>

음, 작동하지 않습니다. 내가 뭘 잘못 했어? 내 자신의 파일 형식을 선언하고 싶습니다.



답변

처리하려는 다양한 상황을 해결하려면 여러 인 텐트 필터가 필요합니다.

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


답변

다른 솔루션은 다음을 추가 할 때까지 안정적으로 작동하지 않았습니다.

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>


답변

에 의해 주어진 answeres Phyrum 차신용장은 이미 매우 유익하다.

Android 7.0 Nougat 부터 앱 간 파일 공유가 처리되는 방식이 변경 되었음을 추가하고 싶습니다 .

공식 Android 7.0 변경 사항 :

Android 7.0을 대상으로하는 앱의 경우 Android 프레임 워크는 앱 외부에 file : // URI를 노출하는 것을 금지하는 StrictMode API 정책을 시행합니다. 파일 URI가 포함 된 인 텐트가 앱을 떠나면 앱은 FileUriExposedException 예외와 함께 실패합니다.

애플리케이션간에 파일을 공유하려면 content : // 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 기기에서 내 활동이 열리지 않도록하는이 작은 변경 사항에 대해 알아 내기가 어려웠습니다. 누군가에게 도움이되기를 바랍니다.


답변

내 결과 :

파일을 검색하는 다양한 방법을 처리하려면 여러 필터가 필요합니다. 즉, 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());
    }
}


답변

그만큼 pathPattern

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

파일 경로에 “.pdf”앞에 하나 이상의 점이 있으면 작동하지 않습니다.

이것은 작동합니다.

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

더 많은 점을 지원하려면 더 추가하십시오.


답변

나는 이것이 오랫동안 작동하도록 노력해 왔으며 기본적으로 모든 제안 된 솔루션을 시도했지만 여전히 Android가 특정 파일 확장자를 인식하도록 할 수 없습니다. 나는 "*/*"작동하는 것처럼 보이는 유일한 MIME 유형을 가진 인 텐트 필터를 가지고 있으며 파일 브라우저는 이제 파일 열기 옵션으로 내 앱을 나열하지만 이제 내 앱은 모든 종류의 파일을 여는 옵션으로 표시됩니다. pathPattern 태그를 사용하여 특정 파일 확장자를 지정했습니다. 지금까지 연락처 목록에서 연락처를 보거나 편집하려고 할 때도 Android에서 내 앱을 사용하여 연락처를 볼 것인지 묻는 메시지가 표시되며, 이는 이러한 상황이 발생하는 여러 상황 중 하나 일뿐입니다.

결국 나는 실제 Android 프레임 워크 엔지니어가 답변 한 비슷한 질문이있는이 Google 그룹 게시물을 발견했습니다. 그녀는 Android는 파일 확장자에 대해 아무것도 모르고 MIME 유형 ( https://groups.google.com/forum/#!topic/android-developers/a7qsSl3vQq0 ) 만 알 수 있다고 설명합니다 .

그래서 제가보고 시도하고 읽은 것에서 안드로이드는 단순히 파일 확장자를 구별 할 수 없으며 pathPattern 태그는 기본적으로 엄청난 시간과 에너지 낭비입니다. 운 좋게도 특정 MIME 유형 (예 : 텍스트, 비디오 또는 오디오)의 파일 만 필요하다면 MIME 유형과 함께 인 텐트 필터를 사용할 수 있습니다. 특정 파일 확장자 또는 Android에서 알지 못하는 MIME 유형이 필요한 경우 운이 좋지 않습니다.

내가 이것에 대해 틀렸다면 지금까지 모든 게시물을 읽고 내가 찾을 수있는 모든 제안 된 솔루션을 시도했지만 아무것도 작동하지 않았습니다.

이런 종류의 일들이 Android에서 얼마나 흔한 지, 개발자 경험이 얼마나 망가 졌는지에 대해 한두 페이지 더 쓸 수는 있지만, 제 분노한 소리를 저장해 드리겠습니다.). 누군가 문제를 해결했으면 좋겠어요


답변

Markus Ressel이 맞습니다. Android 7.0 Nougat는 더 이상 파일 URI를 사용하는 앱 간 파일 공유를 허용하지 않습니다. 콘텐츠 URI를 사용해야합니다. 그러나 콘텐츠 URI는 파일 경로 공유를 허용하지 않고 MIME 유형 만 허용합니다. 따라서 콘텐츠 URI를 사용하여 앱을 자체 파일 확장자와 연결할 수 없습니다.

Drobpox는 Android 7.0에서 흥미로운 동작을합니다. 알 수없는 파일 확장자를 만나면 파일 URI 인 텐트를 형성하는 것처럼 보이지만 인 텐트를 시작하는 대신 운영 체제를 호출하여 인 텐트를 수락 할 수있는 앱을 찾습니다. 해당 파일 URI를 수락 할 수있는 앱이 하나만있는 경우 명시 적 콘텐츠 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);
        ...
    }
}