Can App A start a component in App B through explicit intent?
I understand that general use of an explicit intent is to start a component within the same app. Implicit intents are used to cross process boundary.
Scenario:
App B defines and uses a custom permission "foo"
App A uses
PackageManager API to identify App B (app which defined "foo")
Can App A start a component within App B through explicit intent?
I don't think this is possible because explicit intent needs- app package and component name.
if (PackageManager.PERMISSION_GRANTED == packageManager
.checkPermission("foo",
pk.packageName))
results.add("package name: "+pk.applicationInfo.packageName+ " class name:
"+pk.applicationInfo.classNa);
}
Class name is null. So, per my understanding there is no way inter-app communication is possible through explicit intent just by relying on PackageManager APIs. In Android 5, you can call AIDL Services only through explicit intent but at dev-time the caller needs to know package and component name of app exposing the AIDL. Is my understanding correct?
Can App A start a component within App B?
App A can try. Whether App A will succeed depends on several things, including whether the component is exported and whether the component is secured by a permission.
I don't think this is possible because explicit intent needs- app package and component name.
The application ID and component name are both strings. Apps can use strings. Correctly getting the application ID and component name may take some work, depending upon the relationship between App A and App B.
As a counter-example, the only way to bind to a service on Android 5.0+ is via an explicit Intent. Hence, if App A wishes to bind to a service exported by App B, App A has no choice but to create an explicit Intent.
No way. If you want to start something that's outside your app you have to declare a implicit intent. Otherwise android will look for it inside your package, probably not gonna find anything and crash.
From the docs:
You'll typically use an explicit intent to start a component in your
own app, because you know the class name of the activity or service
you want to start.
Under "Intent Types" - http://developer.android.com/guide/components/intents-filters.html
So, typically you will not... but you can do this however it is not straightforward. To create a proper explicit intent, you will need the application context and the class.
To get the context of another application:
createPackageContext (String packageName, int flags)
http://developer.android.com/reference/android/content/Context.html#createPackageContext(java.lang.String,%20int)
For the class, you can request 'Activity' and 'Service' classes from package manager. You could also try to use reflection. You can also use the fully qualified string name of the package and assume it is correct and/or will not change. If you want, you can include a stub of the class in your app, thereby obtaining a reference to it (if you have access to the source or a stub library).
If there are permission restrictions, you will need to request permission.
Related
I want to fire an intent to another application's activity .
What i am thinking is to use intent filter of the other's.
Or can i access the other application package in some other way?
Suppose My app is 'A' and another app also exist in phone which is 'B'
Q1. Can I access or call classes of B and its method by any means?
Q2. And If it can be done by Implicit Intents then What happens in that case where I cant have access of B's Source code, means I cannot find the B's class Intent filter.
I know that public (named) intents that are registered with the system and can be called from any application and private (anonymous) intents that are used within a single
application. please can anyone give me an example for better understanding.
Thanks in advance
Sorry no time to write a full answer, but you can create custom permissions in order to sign your Intents & BroadcastReceivers.
When you use these custom permissions, only apps that have been signed with the same signing key, and include that custom permission, can see these Intents.
This question might help you:
How to use custom permissions in Android?
#Commonsware explains the issue really well in a recent blog post:
Don't have an Accidental API - The CommonsBlog
The Android documentation does probably the best job of explaining it, here is a relevant snippet:
There are two primary forms of intents you will use.
Explicit Intents have specified a component (via
setComponent(ComponentName) or setClass(Context, Class)), which
provides the exact class to be run. Often these will not include any
other information, simply being a way for an application to launch
various internal activities it has as the user interacts with the
application.
Implicit Intents have not specified a component; instead,
they must include enough information for the system to determine which
of the available components is best to run for that intent. When using
implicit intents, given such an arbitrary intent we need to know what
to do with it.
This is handled by the process of Intent resolution,
which maps an Intent to an Activity, BroadcastReceiver, or Service (or
sometimes two or more activities/receivers) that can handle it.
Explicit intents you use in your activity to start internal activities.
While implicit intents are used often used to launch other activities like when you want to share a link or email something, you send out an implicit intent and let the user decide the email client to use to send the email or to share the link.
There are some instances where you might want to use an implicit intent to run an internal component of your app, because it seems to be more stable.
I have 2 applications A and B.
I want to start an activity in B from A. So I am using an implicit intent. Is there any way to make sure that only the activity in B is invoked by the intent?
i.e In the event that a hacker puts his application on the device trying to receive the same intent, I want to prevent that.
Use the setPackage method to specify whicj app should handle the intent. Here is an example using ZXing:
final String ZXING = "com.google.zxing.client.android";
Intent intent = new Intent(ZXING + ".SCAN");
intent.setPackage(ZXING);
as documention says about android:exported=false:
android:exported
Whether or not the activity can be launched by components of other applications — "true" if it can be, and "false" if not. If "false", the activity can be launched only by components of the same application or applications with the same user ID.
The default value depends on whether the activity contains intent filters. The absence of any filters means that the activity can be invoked only by specifying its exact class name. This implies that the activity is intended only for application-internal use (since others would not know the class name). So in this case, the default value is "false". On the other hand, the presence of at least one filter implies that the activity is intended for external use, so the default value is "true".
This attribute is not the only way to limit an activity's exposure to other applications. You can also use a permission to limit the external entities that can invoke the activity (see the permission attribute).
so ,use android:exported=false in Activity B and use IntentSender in Activty for getting infromation of Intent means from which component want to start your Activty B
If you are using explicit intent, activity specified in intent would be invoked only.
You can add Data, Action, Categories, to limit filtering of component to target only your activity, in case of implicit intent.
You could encrypt any data sent in the intent using a simple Public/Private key encryption. A common approach is to use PGP encryption and Im sure there is a library that is compatible with Android out there.
This would make sure that any hacker would not be able to steal the data sent via intents, as long as they don't have the private key.
That being said, it may be tricky to handle the private key as a good hacker may be able to de-obfuscate/de-compile your application and grab your key. Therefore you may need to keep said key on a central server.
I have an app which uses a service that is included in the application's package.
I am now making a new app which uses a newer version the same service, bundled within its own application package.
If only one app is installed on the device, this works fine. However, if both apps are installed on the device, they both use the service from whichever package was least recently installed -- i.e., the oldest one. This is problematic for two reasons:
1) the old service doesn't handle the new calls (obviously)
2) when using the service bundled with the other app, the service ends up using that other app's saved data instead of its own.
Short-term, I really just want each app to talk to its own version of the service. Is it possible to do this without making each bundled service respond to a unique intent, and having each app use that unique intent?
Long-term, it would be nice to optionally have both apps talk to the newest version of the service, and have them share data, and play nice with either app getting uninstalled. What's the right way to do that? The data is primarily in an SQLite database, which gets stored where Context.getDatabasePath() specifies, which is of course application-specific and wiped if that application is uninstalled.
Here's what I've tried so far:
I can use PackageManager.queryIntentServices() to get a list of ResolveInfo with both versions of the service. By looking at ResolveInfo.serviceInfo.applicationInfo.packageName, I can tell which is which. However, there doesn't seem to be any way to use that ResolveInfo to specify which of the two services I want to handle the intent.
This seems like it should do the right thing:
serviceIntent.setPackage(context.getApplicationContext().getApplicationInfo().packageName);
as that packageName is the same as the one I want to match. Indeed, when I call queryIntentServices with that modified intent I get a list back containing only the service within my package. However, when I try to bindService with that intent, it throws a security exception.
java.lang.RuntimeException: Unable to bind to service my.service.package.name.MyServiceClass#40531558 with Intent { act=my.intent.string pkg=my.app.package.name }: java.lang.SecurityException: Not allowed to start service Intent { act=RuntimeException: Unable to bind to service my.service.package.name.MyServiceClass } without permission private to package
Based on some googling, I have also tried creating the intent by doing:
Intent serviceIntent = new Intent().setClassName(
"my.service.package.name",
"my.service.package.name.ServiceClassName");
That doesn't resolve to any services at all.
I have also tried changing android:exported= in the service entry in the AndroidManifest.xml to true, false, or not specified, in various combinations in both apps, to no avail. (I was hoping that if I set them both to false, then each app would only be able to see its own copy of the service.)
Here is a solution that works:
In the manifest add a meta-data for the Service. The name should be something like "service launcher" and the value must be identical to the name of the action in the intent filter.
<meta-data android:name="Service Launcher"
android:value="your.service.action.string.here" />
<intent-filter>
<action android:name="your.service.action.string.here" />
</intent-filter>
Then in your code add an access method to get the meta-data and use that to build the Intent.
public static String getServiceIntentAction(Context context) {
String action = "";
try {
PackageManager pm = context.getPackageManager();
android.content.ComponentName cn = new android.content.ComponentName(context.getPackageName(), "com.your.ServiceClass");
android.content.pm.ServiceInfo si = pm.getServiceInfo(cn, PackageManager.GET_META_DATA);
action = si.metaData.getString("Service Launcher");
} catch(android.content.pm.PackageManager.NameNotFoundException nnfe) {}
return action;
}
Then anything that is building an Intent to launch the service calls this method. Every user of the service in their app can have a different action to only communicate to their app with just one version of the library and only a change to the manifest.
To have both apps use the same service the service should probably be install as its own entity.
Have you tried using categories? For every category in an intent, the potentially receiving component has to match each category to be considered a receiver.
Service A has category "1" and intents to category "1" go there.
Service B has category "1" and category "2" (assuming it still supports everything in version "1". With this an older app could talk to the newer service but a newer app could not communicate with an older service.
I have written an Android Application and the generated .APK file I uploaded in Android Market. So, a User can download that apk and install in his device.How can I restrict my apk to launch , if he calls from other application through Intent. That means my application should not respond to any intents from other outside Applications.
Is there any possible way to restrict my application's launch from intents from other application.?
I will be waitinig for reply.
Thanks in Advance,
Try setting android:exported="false" to all activities defined at AndroidManifest.xml
That's from activity element description:
android:exported Whether or not the activity can be launched by components of other applications — "true" if it can be, and "false" if not. If "false", the activity can be launched only by components of the same application or applications with the same user ID.
The default value depends on whether the activity contains intent filters. The absence of any filters means that the activity can be invoked only by specifying its exact class name. This implies that the activity is intended only for application-internal use (since others would not know the class name). So in this case, the default value is "false". On the other hand, the presence of at least one filter implies that the activity is intended for external use, so the default value is "true". This attribute is not the only way to limit an activity's exposure to other applications. You can also use a permission to limit the external entities that can invoke the activity (see the permission attribute).
Also here are good paragraphs about application permissions https://developer.android.com/training/articles/security-tips.html I guess you can use that to restrict access to your app.