我有一个自定义文件类型/扩展名,我想将我的应用与。
相关联据我所知,数据元素是为此目的而制作的,但我无法使其正常工作。 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>
嗯,它不起作用。我做错了什么?我只想声明自己的文件类型。
答案 0 :(得分:111)
您需要多个意图过滤器来解决您想要处理的不同情况。
示例1,处理没有mimetypes的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>
答案 1 :(得分:46)
在我添加之前,其他解决方案对我来说无法可靠地工作:
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>
答案 2 :(得分:19)
Phyrum Tea和yuku给出的回复已经非常有用。
我想补充一点,从 Android 7.0 Nougat 开始,处理应用之间文件共享的方式发生了变化:
来自官方Android 7.0 Changes:
对于定位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设备上打开,而旧版本的一切都很好。我希望它有所帮助。
答案 3 :(得分:18)
我的发现:
您需要多个过滤器来处理检索文件的不同方法。即,通过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>
文件资源管理器过滤器:
<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>
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());
}
}
答案 4 :(得分:15)
pathPattern
<data android:pathPattern=".*\\.pdf" />
如果文件路径在“.pdf”之前包含一个或多个点,则不起作用。
这将有效:
<data android:pathPattern=".*\\.pdf" />
<data android:pathPattern=".*\\..*\\.pdf" />
<data android:pathPattern=".*\\..*\\..*\\.pdf" />
<data android:pathPattern=".*\\..*\\..*\\..*\\.pdf" />
如果您想支持更多点,请添加更多。
答案 5 :(得分:4)
Markus Ressel是对的。 Android 7.0 Nougat不再允许使用文件URI在应用程序之间共享文件。必须使用内容URI。但是,内容URI不允许共享文件路径,只允许共享mime类型。因此,您无法使用内容URI将您的应用与自己的文件扩展名相关联。
Drobpox在Android 7.0上有一个有趣的行为。当它遇到未知的文件扩展名时,它似乎形成了文件URI意图,但它没有启动意图,而是调用操作系统来找出哪些应用程序可以接受意图。如果只有一个应用程序可以接受该文件URI,则它会直接向该应用程序发送显式内容URI。因此,要使用Dropbox,您无需更改应用中的intent过滤器。它不需要内容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);
...
}
}
答案 6 :(得分:3)
我一直试图让这个工作多年,并且基本上尝试了所有建议的解决方案,仍然无法让Android识别特定的文件扩展名。我有一个带有"*/*"
mimetype的intent-filter,这是唯一可行的,文件浏览器现在列出我的应用程序作为打开文件的选项,但是我的应用程序现在显示为打开ANY的选项即使我使用pathPattern标记指定了特定的文件扩展名,也要保存文件。到目前为止,即使我尝试在我的联系人列表中查看/编辑联系人,Android也会询问我是否要使用我的应用程序查看联系人,这只是发生这种情况的众多情况之一,非常烦人。
最终我发现这个谷歌群组发布了一个类似的问题,实际的Android框架工程师回答了这个问题。她解释说,Android根本不了解文件扩展名,只知道MIME类型(https://groups.google.com/forum/#!topic/android-developers/a7qsSl3vQq0)。
因此,从我所看到的,尝试和阅读,Android根本无法区分文件扩展名和pathPattern标签基本上是一个巨大的浪费时间和精力。如果您有幸只需要某个mime类型的文件(比如文本,视频或音频),则可以使用具有mime类型的intent-filter。如果您需要特定的文件扩展名或Android不知道的mime类型,那么您就不幸了。
如果我对此有任何不妥之处请告诉我,到目前为止,我已阅读过每篇文章,并尝试了我能找到的所有解决方案,但没有一个有效。
我可以写另外一两页关于这些东西在Android中的常见程度,以及开发者体验如何搞砸了,但我会拯救你愤怒的咆哮;)。希望我救了别人一些麻烦。
答案 7 :(得分:2)
尝试添加
<action android:name="android.intent.action.VIEW"/>
答案 8 :(得分: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类型。我只需要那些项目。
答案 9 :(得分: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文件附件,没有办法解决它
答案 10 :(得分:1)
那些与其他文件管理器\资源管理器应用程序有问题的人,如@yuku和@ phyrum-tea已回答
这适用于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>
答案 11 :(得分: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();
}
答案 12 :(得分:0)
内容URI ftw,以及清单中的intent过滤器...如果您的文件具有自定义扩展名.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类型。现在我可以点击电子邮件中的附件,并在我的应用程序中打开它。
答案 13 :(得分:0)
//我已经尝试过此代码。而且运作良好。您可以使用此代码接受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>
答案 14 :(得分:0)
在kotlin中读取打开文件:
InputStream
答案 15 :(得分:0)
以上解决方案都不适合我,我必须将所有解决方案结合起来才能像这样工作:
<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>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="content"/>
<data android:scheme="file"/>
<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="content"/>
<data android:scheme="file"/>
<data android:host="*"/>
<data android:pathPattern=".*\\.pdf"/>
</intent-filter>
答案 16 :(得分:-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>