【问题标题】:Sharing a file between two specific android apps在两个特定的 Android 应用程序之间共享文件
【发布时间】:2014-08-15 16:32:07
【问题描述】:

我正在编写应用程序 A 和 B。我希望 A 能够向 B 发送任何给定 mime 类型的文件 URI。我找到了一个explanation of how to handle someone making a request for a file,更像是一个拉动,因为我想将一个 URI 从 A 推送到 B,而不需要 B 请求。我也看到了a more generic description of how to share data between apps,但它使用了 ACTION_SEND,在这种情况下,用户将看到一个可供选择的应用程序列表。我只希望应用程序 B 专门接收文件 URI。此外,当有人出于不同目的执行 ACTION_SEND 时,我不希望应用 B 显示为选项。那么,如何将文件 URI 从一个特定应用程序发送到另一个特定应用程序?

编辑 1:在示例中添加一些代码 sn-ps。

在应用 A 中,我正在执行以下操作:

Intent testIntent = new Intent("com.example.appB.TEST");
testIntent.addCategory(Intent.CATEGORY_DEFAULT);
testIntent.setData(Uri.parse("file:///mnt/sdcard/test.txt"));
startActivityForResult(testIntent, TEST);

在应用 B 中,我在清单中有以下内容:

<activity
    android:name="com.example.appB.mainActivity"
    android:label="@string/app_name" 
    android:launchMode="singleTask" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <intent-filter>
        <action android:name="com.example.appB.TEST" />
            <category android:name="android.intent.category.DEFAULT"/>
            <data android:scheme="file"/>
            <data android:mimeType="*/*"/>
    </intent-filter>
</activity>

我得到的错误是 ActivityNotFoundException。如果我去掉 setData 行,活动就会启动,但显然我没有 URI。

您可以阅读我点击here 的更多问题。

【问题讨论】:

  • 什么是用户流?您是否希望从 B 开始一项活动?
  • 用户将使用应用程序 A。他们将单击一个按钮,导致将特定文件发送到应用程序 B 的特定活动。应用程序 B 将解释/处理该文件,然后返回一个 pass/应用 A 的失败结果。

标签: android android-sharing


【解决方案1】:

为您在 B 中的活动致电 startActivity(),将 Uri 放入 Intent。假设您关注the recipe for sharing files via a FileProvider,您只需在Intent 上包含FLAG_ACTIVITY_GRANT_READ_PERMISSION 作为标志,B 将可以临时访问该文件。

Here is a sample project 我通过FileProvider 共享一个 PDF 文件,然后让我的活动启动一个 PDF 查看器以查看该共享文件。在这种情况下,我的应用程序是 A,PDF 查看器应用程序是 B。

【讨论】:

  • 这也是一个很好的解决方案,但与我在回答中提到的了解 B 中的组件有同样的问题。您可以使用自定义 ACTION 字符串来避免这种紧密耦合,但存在另一个活动可能指定该操作字符串来拦截意图的风险。
  • @CommonsWare 我在上面添加了一些代码并且我得到了错误。它类似于您的应用程序在调用意图时所做的事情,但指定了要启动的特定应用程序+活动而不是 ACTION_SEND,并且我忘记添加 FLAG_ACTIVITY_GRANT_READ_PERMISSION,但我认为这不会导致出现异常。我尝试的有什么问题?我将研究如何与示例更相似。
  • @corbin:您可能需要在&lt;data&gt; 中有一个android:scheme 属性来说明您支持的方案。请注意,FLAG_ACTIVITY_GRANT_READ_PERMISSION 用于通过ContentProvider 共享内容;您正在通过文件共享它。请记住,您的方法存在安全问题,尽管您可能只是将其用作早期测试的权宜之计。
  • @CommonsWare 谢谢,我了解安全问题。我设置了方案,见上面的新sn-p。之后同样的例外。
  • @corbin:您能否发布完整的错误,而不仅仅是异常类名称?您也可以尝试匹配 MIME 类型——现在您在 B 中指定 */* 但在 A 中不提供任何内容,虽然我认为它会起作用,但如果您需要,我不会感到惊讶使用setDataAndType() 而不是setData() 并提供非null MIME 类型。
【解决方案2】:

我会使用两个应用程序都知道的自定义 ACTION,这样它就不会使用其他应用程序知道使用的通用 ACTION_SEND。这解决了不希望它出现在 ACTION_SEND 中的问题。这也意味着只有注册您的自定义操作的应用程序才能接收它。不利的一面是,如果其他应用程序知道用于 ACTION 的字符串,则它们可能会收到该意图。

如果您想绝对确定只有 B 可以接收意图,那么您可以指定一个组件。请参阅:https://developer.android.com/reference/android/content/Intent.html#setComponent(android.content.ComponentName) 如果您这样做,则意味着 A 必须知道 B 内部的组件才能将意图定向到,从而使 B 在更改该组件名称方面不太灵活。但这确实意味着来自 A 的意图只能到达 B。

请注意,您仍然不应该信任 B 中的意图。另一个应用程序可以指定操作字符串(反编译您的应用,或查看 logcat 以找到它)和 B 的组件并发送恶意意图。因此,请务必检查 B 中的输入。

【讨论】:

  • 我正在使用自定义操作。请参见上面的代码 sn-ps。但是,如果我使用 setData,我会得到一个 ActivityNotFoundException。
【解决方案3】:

您可以执行以下操作:

1.让App B实现自定义广播接收器。

2.自定义广播只会被App A触发(广播)。

3.App B 将捕获(监听)广播消息,该消息也将包含文件 URI。

您可以为广播添加签名级权限,以便其他应用可以拦截(监听)您的广播。请参阅docs

android:permission 广播者必须的权限名称 必须向广播接收器发送消息。如果这个属性是 未设置,由元素的权限设置的权限 属性适用于广播接收器。如果两个属性都不 设置,接收者不受权限保护。更多 有关权限的信息,请参阅 介绍和单独的文档,安全和权限。

同样,您也可以为您的文件 Uri 添加权限,以使其更安全。

【讨论】:

  • 这有其他应用程序可以拦截自定义广播操作的缺点。使用组件可以避免这种情况,但代价是强制 A 知道 B 中的组件,如上所述。
  • 让我看看这个。我添加了一些代码 sn-ps。我试图做一些更简单的事情,但也许这不起作用?关于拦截这个的另一个应用程序,我并不担心。这将是免费的(如语音)代码,因此指定一个组件将无济于事。
  • @NickPalmer 编辑了答案,因此没有其他应用可以收听我们的广播
  • 添加权限肯定有助于@rupeshjain。
【解决方案4】:

我认为提供的前三个答案都是完成这项工作的正确方法。目前,我正在对我的代码进行一些小的修改。我需要使用 setDataAndType 而不仅仅是 setData。即使应用程序 B 说它可以处理任何 mimeType,但未在应用程序 A 中指定 mimeType 会使这不起作用。

您可以阅读我点击here 的更多问题。

【讨论】:

    【解决方案5】:

    抱歉回复旧帖。

    我可以给出以下场景

    1) 两个应用程序应具有相同的 APPUSERID。

    APP2的工作流要从APP1读取数据

    1)需要APP1的安装信息。 (获取 PackageManager)

    2)调用ApplicationInfo.getApplicationInfo(获取元数据)

    步骤

    1)将APP2中要访问的内容保存在APP1中的一个文件中。

    这是在APP1中

    FileOutputStream fos = null
    File file = null;
    file = getFilesDir();
    fos = openFileOutput("my.txt", Context.MODE_PRIVATE);
    String text = "hello";
    fos.write(text.getBytes());
    

    在APP2中

    String packageName = "your.package.name.of.app1";
    

    2)然后加载APP1中保存的文件

    PackageManager packageManager = getPackageManager();
    
    ApplicationInfo appInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
    
    String filePath = appInfo.dataDir + "/files/my.txt";
    

    3) 然后使用读取文件

    FileInputStream fis = new FileInputStream (new File (filePath));
    // Please write the further code to read the contents of the file 
    

    4) APP1 和 APP2 中的用户 ID 相同,即在 packag="x.y.z" 之后在两个应用程序中写入以下行 AndroidManifest.xml

    android:sharedUserID = "a.b.c"; // 确保在两个应用的清单文件中都包含这一行。这里 a.b.c 和 x.y.z 是原始数据。

    PS:我没有处理异常。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-07
      • 2018-04-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多