Reputation: 1546
I am writing apps A and B. I want A to be able to send B a file URI of any given mime type. I found an explanation of how to handle someone making a request for a file, so more like a pull, where as I want to push a URI from A to B, without B requesting. I have also seen a more generic description of how to share data between apps, but that uses ACTION_SEND and, in that case, the user will be presented with a list of apps to choose from. I only want app B specifically to receive the file URI. In addition, I don't want app B to show up as a choice when someone is doing an ACTION_SEND for a different purpose. So, how do I send a file URI from one specific app to another specific app?
Edit 1: Adding some code snippets to the example.
In app A, I am doing the following:
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);
In app B, I have the following in the manifest:
<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>
The error I get is ActivityNotFoundException. If I get rid of the setData line, the activity is launched, but obviously I don't have the URI.
You can read about more issues I hit here.
Upvotes: 2
Views: 4749
Reputation: 4487
Sorry for answering to an old post.
I can give the below scenario
1)Both apps should have same APPUSERID.
Workflow of APP2 wants to read data from APP1
1)It needs installation information of APP1. (Get the PackageManager)
2)Call ApplicationInfo.getApplicationInfo (Get the META-DATA)
Steps
1)Save the content you want to access in APP2 in a file in APP1.
This is in APP1
FileOutputStream fos = null
File file = null;
file = getFilesDir();
fos = openFileOutput("my.txt", Context.MODE_PRIVATE);
String text = "hello";
fos.write(text.getBytes());
In APP2
String packageName = "your.package.name.of.app1";
2)Then load the file saved in APP1
PackageManager packageManager = getPackageManager();
ApplicationInfo appInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
String filePath = appInfo.dataDir + "/files/my.txt";
3) Then read the file using
FileInputStream fis = new FileInputStream (new File (filePath));
// Please write the further code to read the contents of the file
4)Have the same userID in both APP1 and APP2, i.e. after packag="x.y.z"
write the below line in both applications AndroidManifest.xml
android:sharedUserID = "a.b.c";
// Make sure to include this line in both app's manifest file. Here a.b.c and x.y.z are raw data.
P.S : I have not handled the exceptions.
Upvotes: 0
Reputation: 1546
I think the first three answers provided are all correct ways to make this work. Currently, I am using a small modification of my code. I needed to use setDataAndType and not just setData. Even though app B said it could handle any mimeType, not specifying the mimeType in app A made this not work.
You can read about more issues I hit here.
Upvotes: 0
Reputation: 3430
You can do the following:
1.Make App B implement a custom broadcast receiver.
2.The custom broadcast will only be fired(broadcasted) by App A.
3.App B will catch(listen) the broadcast message which will also contain the file URI.
You can add signature level permission for the broadcast so that other apps can intercept(listen) for your broadcast.refer docs
android:permission The name of a permission that broadcasters must have to send a message to the broadcast receiver. If this attribute is not set, the permission set by the element's permission attribute applies to the broadcast receiver. If neither attribute is set, the receiver is not protected by a permission. For more information on permissions, see the Permissions section in the introduction and a separate document, Security and Permissions.
Similarly you can add permission to your file Uri too,to make it more secure.
Upvotes: 1
Reputation: 2743
I would use a custom ACTION known to both applications so that it isn't using the generic ACTION_SEND that other applications know to use. This solves the problem of not wanting it to show up for ACTION_SEND. It also means that only applications which register for your custom action will be able to receive it. The down side is other applications COULD receive that intent if they know what string to use for the ACTION.
If you want to be absolutely sure that only B can receive the intent then you can specify a component. See: https://developer.android.com/reference/android/content/Intent.html#setComponent(android.content.ComponentName) If you do this it means that A has to know a component inside of B to direct the intent to, making B less flexible in terms of changing that component name. But it does mean the intent from A can only go to B.
Note that you still shouldn't trust the intent in B. Another application COULD specify the action string (decompiling your app, or watching logcat to find it) and B's component and send a malicious intent over. So always check the inputs in B.
Upvotes: 1
Reputation: 1006539
Call startActivity()
for your activity in B, putting the Uri
in the Intent
. Assuming that you are following the recipe for sharing files via a FileProvider
, all you need to do is include FLAG_ACTIVITY_GRANT_READ_PERMISSION
as a flag on the Intent
, and B will have temporary access to the file.
Here is a sample project where I share a PDF file via FileProvider
, then have my activity start up a PDF viewer to go view that shared file. In this case, my app is A, the PDF viewer app is B.
Upvotes: 2