BroadcatReceiver declared in manifest.xml not receiving LocalBroadcastManager intents - android

While it is possible to declare a 'Local' BroadcastReceiver via code so it receives intents published via a LocalBroadcastManager.Ex
LocalBroadcastManager.getInstance(this).registerReceiver(new FooReceiver(), new IntentFilter("foo_intent_filter"));
I wonder if it is possible to declare such receiver via the manifest.xml (cleaner) .
When I use the 'manifest way', the receiver is not 'receiving' the intents.
<receiver
android:name="FooReceiver"
android:enabled="true"
android:exported="false" >
<intent-filter>
<action android:name="foo_intent_filter" />
</intent-filter>
</receiver>
Am I missing something? or the code-way is the only viable solution.
Thanks

I wonder if it is possible to declare such receiver via the manifest.xml (cleaner) .
First, that is not possible.
Second, registering in the manifest has little to do with it being "cleaner". It is to allow Android to instantiate the receiver on its own, so that you can respond to broadcasts when your process is not running. And, in the specific example that you cite, it is to allow any app on the system to send you a broadcast. Neither of those are relevant for LocalBroadcastManager.

Related

Differentiate implicit broadcast receiver vs explicit broadcast receiver in the manifest

According to the migration guide to Android O given by Google, most of the implicit broadcast intent should not be registered in the Manifest (minus a few exceptions found here) but explicit broadcast intents remain untouched.
We are looking to move any needed broadcast away from the manifest. But how do we recognise if a receiver is implicit? Is there a general rule?
Here is a sample of the broadcasts we register in the manifest. Should we look only at the "action" tag and see if it is whitelisted to keep it in the manifest?
<receiver
android:name=".receiver.ImageBroadcastReceiver"
android:enabled="true" >
<intent-filter>
<action android:name="android.hardware.action.NEW_PICTURE" />
<category android:name="android.intent.category.OPENABLE" />
<data android:mimeType="image/*" />
</intent-filter>
</receiver>
<receiver
android:name=".receiver.InstallReferrerReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
<receiver android:name=".receiver.JoinEventReceiver" >
<intent-filter>
<action android:name="JOIN_ACTION" />
<action android:name="CANCEL_ACTION" />
<action android:name="DECLINE_ACTION" />
</intent-filter>
</receiver>
For example, the "com.android.vending.INSTALL_REFERRER" intent is not whitelisted. Should we register it in an Activity? If so wouldn't it be never fired as when we register it the app is already installed? This is what confuses me when trying to understand if a broadcast receiver is implicit or explicit as I thought I only had to check that "action" tag.
But how do we recognise if a receiver is implicit?
If the Intent has a ComponentName, the Intent is explicit. Otherwise, it is implicit.
That ComponentName can be obtained in one of a few ways, including:
It can be directly put on the Intent (e.g., new Intent(this, TheReallyAwesomeReceiver.class)
It can be directly put on the Intent after using PackageManager and queryIntentReceivers() to find the right one based on action strings, etc.
It can be derived by the system from the action string, etc. plus the package defined via setPackage()
Should we look only at the "action" tag and see if it is whitelisted to keep it in the manifest?
No. You also need to think about the nature of the broadcast: is it going to any registered receiver, or only to a specific app?
For example, the "com.android.vending.INSTALL_REFERRER" intent is not whitelisted. Should we register it in an Activity?
No. That broadcast will only go to the app that was recently installed, and so it must be an explicit Intent. The action string and such are there to help the system determine which of your registered receivers is the relevant one.
Contrast that with ACTION_PACKAGE_ADDED. That is broadcast to any registered receiver; it is not going to just one specific app. Hence, that Intent must be implicit (as otherwise it would have a ComponentName identifying a specific receiver in a specific app). And, since ACTION_PACKAGE_ADDED is not on the whitelist, the assumption should be that you cannot register for this broadcast in the manifest on Android 8.0+.

Android: what's the meaning of exported receiver's attribute?

<receiver
android:name="MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
I don't understand if it's needed to be notified.
If it were true any app could call my receiver with those actions? So If I make it false the system can send the actions to my receiver?
I don't understand if it's needed to be notified. If it were true any
app could call my receiver with those actions? So If I make it false
the system can send the actions to my receiver?
Actually, others apps cannot "call your receiver". Other apps can just send broadcast Intents. The System will then call all registered receivers.
In general you shouldn't worry about this. Most of these broadcast Intents are protected so that only system apps can broadcast them anyway. An attempt by another app to broadcast BOOT_COMPLETED, for example, would just be ignored. What would happen if your BroadcastReceiver gets triggered by a rogue app because it broadcast CONNECTIVITY_CHANGE? Probably nothing, because your app should check the real connectivity state in onReceive() anyway, and if there isn't any change you can just ignore it.
Also, you don't need to specify android:enabled="true" because this is the default state. You also don't need to specify android:exported="true" because you have an <intent-filter> attached to your <receiver> which automatically sets android:exported to true.
If you set android:exported ="false", implies that the receiver is intended only for application-internal use.
Note: This attribute is not the only way to limit a broadcast receiver's external exposure. You can also use a permission to limit
the external entities that can send it messages
Adding to #SaravInfern's answer. Here is the relevant permission doc for limiting external entities that can send the receiver messages:
https://developer.android.com/training/permissions/restrict-interactions#broadcast-receivers

Custom permission with implicit intent

In view of the security model in Android, I'm trying to use custom permissions with a broadcast receiver.
WHAT I'VE DONE :
I have declared a custom permission for the receiver, thereby limiting the broadcasts that it can receive. Some code from manifest:
<permission android:name="abc"/>
<receiver android:name=".UpdateUserReceiver"
android:permission="abc"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.ACTION_UPDATE_USERNAME"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
Now I expect that receiver UpdateUserReceiver will only receive broadcasts from components which use the permission 'abc'.
Broadcast sending code:
// Update username. Invoke broadcast.
Intent updateUserBroadcast = new Intent();
updateUserBroadcast.putExtra("username", userName);
updateUserBroadcast.setAction("android.intent.action.ACTION_UPDATE_USERNAME");
sendBroadcast(updateUserBroadcast);
Activity which sends broadcast :
<activity android:name=".UpdateUserNameActivity">
<intent-filter>
<action android:name="com.intent.action.UPDATE_USERNAME"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
Question 1 :
As seen, the activity nowhere uses the permission which the receiver has declared, so that it can receive the broadcast from the activity. But still the receiver is invoked, and I suspect it's due to the use of implicit intents though I'm not sure. Any ideas?
Question 2 :
What's the difference between the permission tag declared at app level, and android:permission tag inside the receiver? I understand the use of 2nd one, which enforces a permission before anyone can expect the receiver to receive the broadcast, but then why's the first one required. Is it needed for this scenario, or can it be removed. Either way, I have checked that the receiver receives the broadcast.
Answer 1:
the <uses-permission> tag in <manifest> requests a permission for all component in this application, you don't need to request a permission for a single activity. And The application declares the custom permission use <permission> will automaticall holds it, no necessary to request it again.
I guess your activity and the receiver are in the same application.
"implicit intents" can not break the "permission rule".
Answer 2:
the <permission> in <application> will set a permission that applies to all of the application's components.
check here:
http://developer.android.com/guide/topics/manifest/application-element.html#prmsn
But still the receiver is invoked, and I suspect it's due to the use of implicit intents though I'm not sure
No.
Any ideas?
They are both in the same app ("because here my activity and receiver are in the same application"). Permissions are applied between apps, as part of inter-process communication (IPC), not within an app.
What's the difference between the permission tag declared at app level, and android:permission tag inside the receiver?
<permission> defines the permission. android:permission applies the permission. To draw a Java analogy, <permission> defines a field, android:permission uses the field.
Ok got your point. you might be sending the broadcast from the same application. Have you tried sending the broadcast from different app? Look at this code. There is a PID check if calling PID is same app then permission will be granted by default. Hence your receiver is getting executed with out any problem.
http://androidxref.com/4.4.4_r1/xref/frameworks/base/core/java/android/app/ActivityManager.java#2109

How to start service using external intent?

I'd like to know if it's possible to start service using intents sent from another app? I've a Broadcast Receiver for android.intent.action.BOOT_COMPLETEDand it works even though at the time when the intent is received BrodcastReceiver class for it is not instancionated. I did something similar for external intents from tasker but it doesn't work.
<receiver android:name="BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
I'd like to know if it's possible to start service using intents sent from another app?
Sure.
I've a Broadcast Receiver for android.intent.action.BOOT_COMPLETEDand it works even though at the time when the intent is received BrodcastReceiver class for it is not instancionated.
That is because manifest-registered BroadcastReceiver objects are not instantiated ahead of time. They are only created when a matching broadcast is sent.
I did something similar for external intents from tasker but it doesn't work.
"it doesn't work" is insufficient information for anyone to help you.
But, if you have a <service> with an <intent-filter>, other apps can create an Intent matching your <intent-filter> and use that to start (or bind to) your service. There are two exceptions:
If you add android:exported="false" to the <service>, third party apps cannot invoke it at all, though you would be better served simply getting rid of the <intent-filter> in that case
If you use android:permission on the <service> element, the other app needs to hold your stated permission in order to start or bind to your service

Restrict Broadcast Receiver to application

I am working on broadcast receiver and stuck in a problem.
I am receiving a broadcast receiver in Manifest file.
<receiver class=".MyClass" android:name=".MyClass">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.net.ConnectivityManager.CONNECTIVITY_ACTION" />
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
</intent-filter>
</receiver>
this is working fine and it is calling MyClass whenever there is change in connectivity.
Now the problem is whenever my application is not running still this class will receive broadcast receiver. I want it to receive whenever the application is running.
I tried it by extending BroadcastReceiver registering and unregistering broadcast in that class file and it works. But i want to achieve the same by Manifest file.
My problem will solve if it is not receiving anything when application is not opened.
What you are talking is not possible. The whole purpose of having the intent filter in the manifest is being able to receive the intent whether or not your application is running. The only way to do what you want to is by registering/unregistering the receiver from the code [registerReceiver]
The question was asked a long time ago but in case some one landed on this page while searching, It is possible to register and unregister broadcast receiver from code instead of doing that from manifest file. (Checking the Networking Connectivity using BroadcastReceiver in Android)
You said "My problem will solve if it is not receiving anything when application is not opened".
Here how I understand your question and appropriate answer.
android:enabled
Whether or not the broadcast receiver can be instantiated by the system — "true" if it can be, and "false" if not. The default value is "true".
If you want to enable your receiver at runtime, you can set the state to disabled initially. You can do so in the manifest file:
<receiver
android:name=".YourReceiver"
android:enabled="false" >
<!-- your intent filter -->
</receiver>
Source:
http://developer.android.com/guide/topics/manifest/receiver-element.html#enabled
http://www.grokkingandroid.com/enabling-and-disabling-broadcastreceivers/

Categories

Resources