Android Studio 3.2
public class GcmWakefulBroadcastReceiver extends WakefulBroadcastReceiver {
private static String TAG;
#Override
public void onReceive(Context context, Intent intent) {
ComponentName comp = new ComponentName(context.getPackageName(), GcmIntentService_.class.getName());
startWakefulService(context, (intent.setComponent(comp))); // crash here
setResultCode(Activity.RESULT_OK);
}
}
public class GcmIntentService extends IntentService {
private static String TAG = GcmIntentService.class.getName();
public GcmIntentService() {
super(TAG);
}
#Override
protected void onHandleIntent(Intent intent) {
}
}
On Android 8.0- success work. App is on background.
But on Android 8.0+ the app is crash with error:
FATAL EXCEPTION: main
Process: com.myproject.app, PID: 6506
java.lang.RuntimeException: Unable to start receiver com.myproject.app.gcm.GcmWakefulBroadcastReceiver: java.lang.IllegalStateException: Not allowed to start service Intent { act=com.google.android.c2dm.intent.RECEIVE flg=0x1000010 pkg=com.myproject.app cmp=com.myproject.app/.gcm.GcmIntentService_ (has extras) }: app is in background uid UidRecord{27efe68 u0a164 RCVR idle change:idle|uncached procs:1 seq(0,0,0)}
at android.app.ActivityThread.handleReceiver(ActivityThread.java:3194)
at android.app.ActivityThread.-wrap17(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1672)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: java.lang.IllegalStateException: Not allowed to start service Intent { act=com.google.android.c2dm.intent.RECEIVE flg=0x1000010 pkg=com.myproject.app cmp=com.myproject.app/.gcm.GcmIntentService_ (has extras) }: app is in background uid UidRecord{27efe68 u0a164 RCVR idle change:idle|uncached procs:1 seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1521)
at android.app.ContextImpl.startService(ContextImpl.java:1477)
at android.content.ContextWrapper.startService(ContextWrapper.java:650)
at android.content.ContextWrapper.startService(ContextWrapper.java:650)
at com.myproject.app.gcm.GcmWakefulBroadcastReceiver.onReceive(GcmWakefulBroadcastReceiver.java:44)
at android.app.ActivityThread.handleReceiver(ActivityThread.java:3187)
... 8 more
broadcast intent callback: result=CANCELLED
Crash in this line:
startWakefulService(context, (intent.setComponent(comp))); // crash here
My app must work on Android 4.4+
Use JobIntentService Instead of IntentService.
public class GcmIntentService extends JobIntentService {
private static String TAG = GcmIntentService.class.getName();
public static void startService(Context context) {
enqueueWork(context, GcmIntentService.class, 1001, new Intent());
}
#Override
protected void onHandleWork(Intent intent) {
}
}
And From your Receiver:
public class GcmWakefulBroadcastReceiver extends WakefulBroadcastReceiver {
private static String TAG;
#Override
public void onReceive(Context context, Intent intent) {
GcmIntentService.startService(context);
}
}
If you are using GcmWakefulBroadcastReceiver just for starting the service then, You do not need to use WakefulBroadcastReceiver.
When running on Android O, the JobScheduler will take care of wake
locks for you (holding a wake lock from the time you enqueue work
until the job has been dispatched and while it is running).
https://developer.android.com/reference/android/support/v4/app/JobIntentService
Related
We just migrated app's target api to Android API 27 (8.1) and it keeps on crashing when notification arrives specially when the app is in the background.
java.lang.RuntimeException: Unable to start receiver <package>.service.GCMBroadcastReceiver: java.lang.IllegalStateException: Not allowed to start service Intent { act=com.google.android.c2dm.intent.RECEIVE flg=0x1000010 pkg=<package> cmp=<package>/.service.GCMIntentService (has extras) }: app is in background uid UidRecord{b248a9d u0a85 RCVR bg:+1m4s53ms idle change:uncached procs:1 seq(0,0,0)}
at android.app.ActivityThread.handleReceiver(ActivityThread.java:3194)
at android.app.ActivityThread.-wrap17(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1672)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: java.lang.IllegalStateException: Not allowed to start service Intent { act=com.google.android.c2dm.intent.RECEIVE flg=0x1000010 pkg=<package> cmp=<package>/.service.GCMIntentService (has extras) }: app is in background uid UidRecord{b248a9d u0a85 RCVR bg:+1m4s53ms idle change:uncached procs:1 seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1521)
at android.app.ContextImpl.startService(ContextImpl.java:1477)
at android.content.ContextWrapper.startService(ContextWrapper.java:650)
at android.support.v4.content.WakefulBroadcastReceiver.startWakefulService(WakefulBroadcastReceiver.java:99)
at <package>.service.GCMBroadcastReceiver.onReceive(GCMBroadcastReceiver.java:32)
at android.app.ActivityThread.handleReceiver(ActivityThread.java:3187)
at android.app.ActivityThread.-wrap17(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1672)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
This is how I fix the issue:
Why this issue happens?
Due to the new Background Execution Limits of Android 8 and you should
not start services background.
How I fixed it
Migrate your GCMIntetService to JobIntentService instead of IntentService.
Please follow this steps:
1) Add the BIND_JOB_SERVICE permission to your service:
<service android:name=".service.GCMIntentService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE"/>
2) In your GCMIntentService, instead extending the IntentService, use android.support.v4.app.JobIntentService and override onHandleWork
then remove the override in you onHandleIntent.
public class GCMIntentService extends JobIntentService {
// Service unique ID
static final int SERVICE_JOB_ID = 50;
// Enqueuing work in to this service.
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, GCMIntentService.class, SERVICE_JOB_ID, work);
}
#Override
protected void onHandleWork(#NonNull Intent intent) {
onHandleIntent(intent);
}
private void onHandleIntent(Intent intent) {
//Handling of notification goes here
}
}
Then finally, in your GCMBroadcastReceiver, enqueue your GCMIntentService.
public class GCMBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GCMIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
// startWakefulService(context, (intent.setComponent(comp)));
//setResultCode(Activity.RESULT_OK);
GCMIntentService.enqueueWork(context, (intent.setComponent(comp)));
}
}
This implementation work for me after we update our target sdk to 27 and I hope it works for you.
I want to open my android app as soon as notification is arrived without user interaction . But as my BroadcastReceiver cannot extend Activity so how I will I open another activity (as it requires Intent).
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ComponentName comp = new ComponentName(context.getPackageName(),
GCMNotificationIntentService.class.getName());
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
I'm trying to use startWakefulService(context, intent)
But after encoutering some issues I debugged my app and found that the intent being passed on to the method is false, it uses
Intent { act=com.google.android.c2dm.intent.RECEIVE flg=0x10 pkg=com.myApp.beta cmp=com.myApp.beta/fonctionnalite.Actualites.GcmReceiver (has extras) }
Instead of
Intent { act=com.google.android.c2dm.intent.RECEIVE flg=0x10 pkg=fonctionnalite.Actualites cmp=fonctionnalite.Actualites.GcmReceiver (has extras) }
So basically I'm trying to call the class called GcmReceiver which is in the package fonctionnalite.Actualites. I tried using a different component and intent but it still didn't work, would anyone know how I can solve this problem ?
Thanks !
Here is the code for the class using startWakefulService
public class GcmReceiver extends WakefulBroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
ComponentName comp = new ComponentName(context.getPackageName(), GcmMessageHandler.class.getName());
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
So, I have this problem.
I'm using a dependency project that is some kind of GCM notification parser. It's a bit poorly written, however I'm forced to use it, becase of work related reasons. Anyways:
The main service (that extends IntentService) is launched with WakefulBroadcastReceiver.
After it receives message from GCM I does some magic and sends it to the main App using broadcast.
In main app I'm constantly running service with another BroadcastReceiver that catches messages and saves everything in database etc.
Why is it so complicated? Firstly - originally it was someone else's project and now I'm trying to fix bugs. Secondly - I have no access from dependency to the main application project so I pass messages with broadcasts.
And now, the fun part. I need to filter whether I want to show notification or not. While sending a message to my main AppService I check it with the history of previous messages and then I decide if I need to show this message to User or not. However, no matter what my decision is, my dependency still shows my notification.
So I added yet another broadcast, when after successful validation I launch in my dependency notification building method.
Here is the code:
My WakefulBroadcastReceiver:
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ComponentName comp = new ComponentName(context.getPackageName(), PushService.class.getName());
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
Here is my Depencency service
public NotificationCheckerReceiver notificationCheckerReceiver;
...
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
String messageType = gcm.getMessageType(intent);
if (!extras.isEmpty()) {
if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
//Launch my "approval" receiving broadcast
launchBroadcastReceiver(extras, intent);
//send broadcast to main app with the message we will parse etc.
sendSmsBroadcast(...));
}
}
}
#Override
public void onDestroy() {
unregisterReceiver(notificationCheckerReceiver);
super.onDestroy();
}
//Launch to build notification
public void showNotification(Bundle extras){
...
//Basic notification builder
}
//Receive broadcast from DB if notification was already in the DB
private void launchBroadcastReceiver(Bundle extras, Intent intent){
Log.d(TAG, "Broadcast receiver loaded");
notificationCheckerReceiver = new NotificationCheckerReceiver(new NotiFlag() {
#Override
public void onReceiveApproval(Boolean flag, Intent intent, Bundle extras) {
Log.d(TAG, "Approved notification show");
showNotification(extras);
JustPushGcmBroadcastReceiver.completeWakefulIntent(intent);
}
}, intent, extras);
registerReceiver(notificationCheckerReceiver, new IntentFilter(notificationCheckerReceiver.INTENT_EVENT_NAME));
}
public void sendSmsBroadcast(String message, boolean isAppOnScreen){
...
//This works
}
}
and my "faulty" receiver:
public class NotificationCheckerReceiver extends BroadcastReceiver{
private final String TAG = getClass().getSimpleName();
public static final String INTENT_EVENT_NAME = "NOTIFLAG";
public static final String INTENT_FLAG_KEY = "FLAG";
Intent intent;
Bundle extras;
NotiFlag nofiFlag;
public NotificationCheckerReceiver(NotiFlag nofiFlag, Intent intent, Bundle extras){
Log.d(TAG, "Launched constructor NotificationChecker");
this.nofiFlag = nofiFlag;
this.intent = intent;
this.extras = extras;
}
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Launched onReceive");
Boolean bool = intent.getExtras().getBoolean(INTENT_FLAG_KEY);
Log.d(TAG, "___________Broadcast receiver got something and it is intent: "+bool);
if (bool != false) {
nofiFlag.onReceiveApproval(bool, this.intent, this.extras);
}
}
}
and lastly, what I'm sending from my main service:
public void sendNotificationCheckerBroadcast(Boolean message){
Intent flag = new Intent(NotificationCheckerReceiver.INTENT_EVENT_NAME);
flag.putExtra(NotificationCheckerReceiver.INTENT_FLAG_KEY, message);
DvLogs.d(TAG, "__________Sending intent: "+message);
sendBroadcast(flag);
}
What happens is that eveything to the point where I launch "sendNotificationCheckerBroadcast()". I get that I'm sending some kind of boolean... and that's it.
The funny part is: it SOMETIMES works.
I don't know why, but when for some reason it launches - everything is awesome.
EDIT:
When it works, because sometimes it does, I have this error:
01-15 11:20:22.204 3234-3234/pl.digitalvirgo.lafarge E/ActivityThread﹕ Service com.example.name.PushService has leaked IntentReceiver com.example.name.NotificationCheckerReceiver#43042b50 that was originally registered here. Are you missing a call to unregisterReceiver()?
android.app.IntentReceiverLeaked: Service com.example.name.PushService has leaked IntentReceiver com.example.name.NotificationCheckerReceiver#43042b50 that was originally registered here. Are you missing a call to unregisterReceiver()?
at android.app.LoadedApk$ReceiverDispatcher.<init>(LoadedApk.java:814)
at android.app.LoadedApk.getReceiverDispatcher(LoadedApk.java:610)
at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:1772)
at android.app.ContextImpl.registerReceiver(ContextImpl.java:1752)
at android.app.ContextImpl.registerReceiver(ContextImpl.java:1746)
at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:479)
at com.example.name.PushService.launchBroadcastReceiver(Unknown Source)
at com.example.name.PushService.onHandleIntent(Unknown Source)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:157)
at android.os.HandlerThread.run(HandlerThread.java:61)
Maybe it's somehow related?
I know that I should unRegister this Receiver ... somewhere. Tried onStop, but as we can see - no success.
Edit2:
Weird.
I believe, that the problem is in onStop() method. Probably it's called too early (?) so my Receiver has no chance to work. When I launch app without unRegister everything works. Of course I get bug above, but still... it's something.
Any ideas guys?
Well. The problem was inside the idea of IntentService.
intentService kills itself after onHandleIntent() method.
So the solution for this problem is to change IntentService into Service remembering to handle stopping this thing.
Using setComponentEnabledSetting causes the android os to restart upon uninstall. Has anyone else come across this?
ERROR/AndroidRuntime(1143): * FATAL EXCEPTION IN SYSTEM PROCESS: android.server.ServerThread
java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.PACKAGE_CHANGED dat=package:com.example.foo flg=0x8000010 (has extras) } in com.android.server.NotificationManagerService$2#41b00228
Caused by: java.lang.IllegalArgumentException: Unknown package: com.example.foo
at com.android.server.pm.Settings.getApplicationEnabledSettingLPr(Settings.java:2443)
Here's the code :
public class FooActivity extends Activity {
#Override
protected void onResume() {
super.onResume();
enableReceiver();
}
#Override
protected void onPause() {
super.onPause();
disableReceiver();
}
private void enableReceiver() {
setReceiverState(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
}
private void disableReceiver() {
setReceiverState(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
}
private void setReceiverState(int receiverState) {
getPackageManager().setComponentEnabledSetting(new ComponentName(this, FooBroadcastReceiver.class), receiverState, PackageManager.DONT_KILL_APP);
}
public static class FooBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
}
}
}
the receiver in the manifest :
<receiver android:name="com.example.foo.FooActivity$FooBroadcastReceiver"/>
thanks!
It sounds like you registered a BroadcastReceiver for the android.intent.action.PACKAGE_CHANGED Intent inside your activity, changed its state and then uninstalled the package. The crash does sound like a bug, but I'm guessing while the receiver was still registered the notification manager tried to deliver the uninstall and then crashed.
You might want to call setReceiverState(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT); before you uninstall?
I had the same problem, and solved it by not setting the DONT_KILL_APP flag.
getPackageManager().setComponentEnabledSetting(new ComponentName(this,
FooBroadcastReceiver.class), receiverState, 0);