在Android中注册一个新的文件类型

22

我想在Android上编写一个简单的STL(几何数据文件)查看器应用程序,但我无法让系统识别格式。我在我的应用程序清单文件中编写了以下内容:

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <action android:name="android.intent.action.EDIT" />
    <action android:name="android.intent.action.PICK" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="http" />
    <data android:pathPattern=".*\\.stl" />
    <data android:mimeType="application/sla" />
    <data android:host="*" />
</intent-filter>

但是当我启动浏览器并尝试下载一些样例STL文件时,下载被中断并报告系统无法识别数据文件类型。

我没有真正的Android设备,所以我只使用模拟器,而开发方面我使用MonoDroid上的C#(但我真的不认为这是问题所在)。

我该如何解决这个问题?


我只是猜测,但你可以尝试省略主机元素。此外,logcat 可能会向你展示哪个意图以及使用了什么模式,这样你就可以更好地理解系统正在寻找什么。 - Heiko Rupp
5个回答

23

我正在使用这个清单来注册(例如)一个.stl文件类型到我的应用程序:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.test.core" android:versionCode="1" android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".Testy" android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name="ThorActivity" android:label="@string/app_name">
        </activity>

        <activity android:name="LokiActivity" android:label="@string/app_name">
        </activity>

        <activity android:name="OdinActivity" android:label="@string/app_name">
            <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=".*\\.stl" />
                <data android:scheme="https" android:host="*"
                    android:pathPattern=".*\\.stl" />
                <data android:scheme="content" android:host="*"
                    android:pathPattern=".*\\.stl" />
                <data android:scheme="file" android:host="*"
                    android:pathPattern=".*\\.stl" />
            </intent-filter>
        </activity>
    </application>

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

</manifest>

正如您所看到的,我将 .stl 文件扩展名与活动 OdinActivity 相关联。 在 OdinActivity 内部,我使用以下行获取文件路径,以便打开它:

filePath = getIntent().getData().getEncodedPath();

然后我只需打开它并从中读取:

FileOutputStream out = new FileOutputStream(new File(filePath));

嗯...我尝试将.mmmm格式更改为众所周知的格式(我使用PDF)。转到我的GMail帐户并尝试从其中一封邮件中下载DPF。我得到了完全相同的负面结果。因此,我有些怀疑:我是否需要实现自定义ContentProvider来明确声明Android将要下载数据的位置?对我来说,支持自定义格式如此棘手真的很奇怪... :( - Tigran
嗯...你试过.pdf文件吗?由于这是一种非常常见的文件类型,可能已经被注册到另一个应用程序中了。我不知道你是否可以使用你的程序覆盖该设置。你尝试过你想要的文件类型STL吗? 如果你只是想在你的智能手机上关联文件,并且不介意它不是通过代码实现的,你可以这样做: 菜单->设置->应用程序->管理应用程序,选择现在默认的应用程序,然后点击“清除默认”按钮。 - gnclmorais
是的,我也尝试过使用STL。所以我尝试使用PDF,因为它是众所周知的格式,几乎被所有人支持,以便了解问题出在哪里。但奇怪的是,即使使用PDF,我得到了与我之前写的一样的负面结果。我使用的是模拟器而不是真实设备,所以我想知道在这种情况下使用模拟器是否有问题。 - Tigran
请检查我的第一个答案,我进行了编辑以包含更多关于如何实现它的细节。希望能对您有所帮助。 - gnclmorais
我需要包含哪些权限?什么是 MIME 类型? - madan V

8

我很惊讶 gnclmorais的解决方案能够起作用。因为它在一个intent-filter中有多个data条目,而对我来说并没有起作用。最终起作用的是在一个activity中有多个intent-filter

<activity
  android:description='@string/Activity_Description'
  android:icon='@drawable/ic_launcher'
  android:label='@string/Activity_Name'
  android:name='net.sourceforge.uiq3.fx603p.Calculator_Activity'
>
  <intent-filter>
    <action
      android:name='android.intent.action.MAIN'
    ></action>
    <category
      android:name='android.intent.category.LAUNCHER'
    ></category>
  </intent-filter>
  <intent-filter
    android:icon='@drawable/ic_fx_603p_pf'
    android:label='FX-603P Simulator Program'
    android:priority='1'
  >
    <category
      android:name='android.intent.category.DEFAULT'
    ></category>
    <action
      android:name='android.intent.action.VIEW'
    ></action>
    <data
      android:host='*'
      android:pathPattern='.*\\.pf'
      android:scheme='file'
    ></data>
  </intent-filter>
  <intent-filter
    android:icon='@drawable/ic_fx_603p_df'
    android:label='FX-603P Simulator Datafile'
    android:priority='1'
  >
    <category
      android:name='android.intent.category.DEFAULT'
    ></category>
    <action
      android:name='android.intent.action.VIEW'
    ></action>
    <data
      android:host='*'
      android:pathPattern='.*\\.df'
      android:scheme='file'
    ></data>
  </intent-filter>
  <intent-filter
    android:icon='@drawable/ic_fx_603p_af'
    android:label='FX-603P Simulator Allfile (Data and Program)'
    android:priority='1'
  >
    <category
      android:name='android.intent.category.DEFAULT'
    ></category>
    <action
      android:name='android.intent.action.VIEW'
    ></action>
    <data
      android:host='*'
      android:pathPattern='.*\\.af'
      android:scheme='file'
    ></data>
  </intent-filter>
  <intent-filter
    android:icon='@drawable/ic_fx_603p_pf'
    android:label='FX-603P Simulator Program'
    android:priority='1'
  >
    <category
      android:name='android.intent.category.DEFAULT'
    ></category>
    <action
      android:name='android.intent.action.VIEW'
    ></action>
    <data
      android:host='*'
      android:mimeType='application/x-fx-602p.program'
    ></data>
  </intent-filter>
  <intent-filter
    android:icon='@drawable/ic_fx_603p_df'
    android:label='FX-603P Simulator Datafile'
    android:priority='1'
  >
    <category
      android:name='android.intent.category.DEFAULT'
    ></category>
    <action
      android:name='android.intent.action.VIEW'
    ></action>
    <data
      android:host='*'
      android:mimeType='application/x-fx-602p.data'
    ></data>
  </intent-filter>
  <intent-filter
    android:icon='@drawable/ic_fx_603p_af'
    android:label='FX-603P Simulator Allfile (Data and Program)'
    android:priority='1'
  >
    <category
      android:name='android.intent.category.DEFAULT'
    ></category>
    <action
      android:name='android.intent.action.VIEW'
    ></action>
    <data
      android:host='*'
      android:mimeType='application/x-fx-602p.all'
    ></data>
  </intent-filter>
</activity>

请注意,在一个 data 条目中同时拥有 pathPatternmimeType 也不起作用。最后,但并非最不重要的是,在获取文件名时建议进行一些空值检查:
   /**
    * <p>Open calculator and load file (if one was passed).</p>
    * @see android.app.Activity#onStart()
    */
   @Override
   public void onStart ()
   {
      android.util.Log.d (Calculator_Activity.TAG, "+ onStart");
      super.onStart ();

      final android.content.Intent intent = getIntent ();

      if (intent != null)
      {
         android.util.Log.d (Calculator_Activity.TAG, "> Got intent : " + intent);

         final android.net.Uri data = intent.getData ();

         if (data != null)
         {
            android.util.Log.d (Calculator_Activity.TAG, "> Got data   : " + data);

            final String filePath = data.getEncodedPath ();

            android.util.Log.d (Calculator_Activity.TAG, "> Open file  : " + filePath);

            // File loading comes here.
         } // if
      } // if
      android.util.Log.d (Calculator_Activity.TAG, "- onStart");
      return;
   } // onStart

样例中缺少文件的实际加载。在“打开文件”日志命令之后应插入它。

1
我很惊讶你感到惊讶 :). 你看,gnclmorais的解决方案仅用于一个文件扩展名(stl),而你的解决方案涉及不同的文件扩展名(pf、df、af等)。显然,你必须为每个扩展名使用多个意图过滤器。 - Stan
@Stan,为什么多个android:scheme会比多个android:pathPattern更好?我看不出任何明显的原因。有些晦涩的原因 - 是的,总是有这样的原因。但不是显而易见的。请注意,如果您查看http://developer.android.com/reference/android/content/Intent.html,您将看到所有示例每个意图只有一个`<data>`部分。 - Martin
“application/x-fx-602p.all” 是什么类型的 MIME 类型?它是如何构建的?您是否以某种方式将其注册,以便系统能够识别它? - AareP
它是一种“x-”类型。这是用户自定义的类型。每个人都可以在需要时定义“x-”类型。 - Martin

7

我尝试了其他解决方案,但只有这个对我有效:

<intent-filter
    android:icon="@drawable/icon"
    android:label="Armro File"
    android:priority="1" >
    <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" />
    <data android:scheme="https" />
    <data android:scheme="ftp" />
    <data android:scheme="file" />
    <data android:host="*" />
    <data android:mimeType="*/*" />
    <data android:pathPattern=".*\\.myowntype" />
</intent-filter>

为什么其他的不起作用呢?

我不知道为什么其他的方法不起作用,但只有这个对我有效。另外,谢谢。 - abbasalim

3

尝试按以下格式识别:

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

0

使用intent-filters时,我遇到了几个陷阱,但最终在这里找到了一个可行的示例:Android intent filter not working,在Tim Autin的回答中。

  • Android的路径模式匹配器是以非贪婪方式实现的,这就是为什么有几个答案建议添加多个路径模式(参见pathPattern to match file extension does not work if a period exists elsewhere in the file name?)。对我而言,以斜杠开头的模式效果最佳(即)
    <data android:pathPatern="/.*..*..*..*..*\\.myextension" />
  • 使用mime类型过滤器和文件名过滤器的组合可能会过滤太多,因此我最终采用了一个用于文件扩展名的意图过滤器和另一个用于mime类型的意图过滤器
  • 对于文件扩展名,我不知何故需要两个意图过滤器:一个用于通配符mimetype<data android:mimeType="*/*" />,另一个意图过滤器的标签中根本没有mime类型。

因此,像提议的那样使用这三个意图过滤器最终奏效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接