问题
I was trying to get notification trigger on my application whenever the user makes a new call. I'm registering receiver in my activity and destroying it in onDestroy() method. Following is the code snippets for registering
registerReceiver(inComingCall = new IncomingCall(),new IntentFilter("android.intent.action.PHONE_STATE"));
The issue I'm facing is I'm not getting any trigger in override onReceive() method for the Broadcast receiver. Kindly let me know whether any new implementations or the separate way I should do for receiving the broadcast especially for Oreo.
Thanks in Advance.
回答1:
I faced this issue for a long time. And every one will provide you a link to google developers site, which describes nothing than how they are having limits on background services; with no proper documentation and no sample code showing developers, how to implement it on Oreo or Higher. Even on stack-Overflow you will find only links to the google developers site on limitations.
I hope you or some other developer will find this very helpful.
There are still some exclusions like NEW_OUTGOING_CALL
OR BOOT_COMPLETED
which you can still use in manifest. But its a good practise to implement runtime at application context. I wanted my PHONE_STATE
ready always for getting incoming and outgoing calls; On every reboot too...
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.rushi.boottest">
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="26" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service
android:name=".CatchNumbers"
android:enabled="true"
android:exported="true" />
<service
android:name=".WatchMan"
android:enabled="true"
android:exported="true"></service>
</application>
</manifest>
In above manifest.xml i have not placed WRITE_EXTERNAL_STORAGE
and READ_EXTERNAL_STORAGE
. It has automatically inserted by android studio as i implemented it runtime.
Here is my OnBoot Receiver :
package com.example.rushi.boottest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;
public class MyReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
Log.d("BootTest : ", "\nOnBootReceiver - Received a broadcast!");
Toast.makeText(context, "OnBootReceiver Received a broadcast!!", Toast.LENGTH_LONG).show();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
context.startForegroundService(new Intent(context, WatchMan.class));
}
else
{
context.startService(new Intent(context, WatchMan.class));
}
}
}
Here is WatchMan.java a foreground service that implements receivers runtime
public class WatchMan extends Service
{
NotificationManager mNotifyManager;
NotificationCompat.Builder mBuilder;
NotificationChannel notificationChannel;
String NOTIFICATION_CHANNEL_ID = "17";
private BroadcastReceiver mCallBroadcastReceiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
String PhoneNumber = "UNKNOWN";
Log.d("RECEIVER : ","IS UP AGAIN....");
try
{
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if(state == null)
{
PhoneNumber = "UNKNOWN";
}
else if (state.equals(TelephonyManager.EXTRA_STATE_RINGING))
{
PhoneNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
Log.d("RECEIVER : ","Incoming number : "+PhoneNumber);
}
if(intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL"))
{
PhoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.d("RECEIVER : ","Outgoing number : "+PhoneNumber);
}
if(!PhoneNumber.contentEquals("UNKNOWN"))
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
context.startForegroundService(new Intent(context, CatchNumbers.class));
}
else
{
context.startService(new Intent(context, CatchNumbers.class));
}
}
}
catch (Exception e)
{
e.printStackTrace();
Log.e("RECEIVER : ", "Exception is : ", e);
}
}
};
public WatchMan() { }
@Override
public void onCreate()
{
super.onCreate();
Log.d("WatchMan : ", "\nOnCreate...");
IntentFilter CallFilter = new IntentFilter();
CallFilter.addAction("android.intent.action.NEW_OUTGOING_CALL");
CallFilter.addAction("android.intent.action.PHONE_STATE");
this.registerReceiver(mCallBroadcastReceiver, CallFilter);
Log.d("WatchMan : ", "\nmCallBroadcastReceiver Created....");
mNotifyManager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this, null);
mBuilder.setContentTitle("Insta Promo")
.setContentText("Checking New Numbers")
.setTicker("Checking New Numbers")
.setSmallIcon(R.drawable.ic_launcher_background)
.setPriority(Notification.PRIORITY_LOW)
.setDefaults(Notification.DEFAULT_ALL)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setOngoing(true)
.setAutoCancel(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Notifications", NotificationManager.IMPORTANCE_HIGH);
// Configure the notification channel.
notificationChannel.setDescription("Channel description");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
notificationChannel.enableVibration(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
mNotifyManager.createNotificationChannel(notificationChannel);
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
startForeground(17, mBuilder.build());
}
else
{
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
//startForeground(17, mBuilder.build());
mNotifyManager.notify(17, mBuilder.build());
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d("WatchMan : ", "\nmCallBroadcastReceiver Listening....");
//return super.onStartCommand(intent, flags, startId);
return START_NOT_STICKY;
}
@Override
public void onDestroy()
{
this.unregisterReceiver(mCallBroadcastReceiver);
Log.d("WatchMan : ", "\nDestroyed....");
Log.d("WatchMan : ", "\nWill be created again....");
}
@Override
public IBinder onBind(Intent intent)
{
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
Now in the receiver before calling insert phone numbers into sqlite
database table; so that you can read it from CatchNumbers.java service and perform whatever actions you wants on incoming and outgoing numbers. Hope it helps you or someone else
回答2:
The solution of Sandhya Sasane work for me on the android 9 emulator the BOOT_COMPLETED notification is received (either forcing it via "adb" or rebooting the emulator).
But on a real device Huawei P-Smart with EMUI 9.1.0.119 never happens :(
回答3:
I also had this kind of issue, but I found a better solution:
@BroadcastReceiverActions({"android.intent.action.SCREEN_ON", "android.intent.action.SCREEN_OFF",
"android.intent.action.DREAMING_STARTED", "android.intent.action.DREAMING_STOPPED",
"android.intent.action.ACTION_POWER_DISCONNECTED", "android.intent.action.ACTION_POWER_CONNECTED",
"android.net.conn.CONNECTIVITY_CHANGE"})
public class MyReceiver extends BroadcastReceiver {
public MyReceiver() {
super();
}
@Override
public void onReceive(Context context, Intent intent) {
Session.getGlobalReceiverCallBack(context, intent);
//Log.e("dfd", "" + intent.getAction());
}
}
public class AppController extends Application {
private BroadcastReceiver receiver;
MyReceiver mR;
@Override
public void onCreate() {
super.onCreate();
mR = new MyReceiver();
receiver = DynamicReceiver.with(mR)
.register(this);
}
}
public class MainActivity extends AppCompatActivity implements GlobalReceiverCallBack {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Session.setmGlobalReceiverCallback(this);
}
@Override
public void onCallBackReceived(Context context, Intent intent) {
Toast.makeText(context, "" + intent.getAction(), Toast.LENGTH_LONG).show();
}
}
For complete reference you can see also https://github.com/devggaurav/BroadcastReceiver-For-Naught-and-Oreo-devices
来源:https://stackoverflow.com/questions/49573303/oreo-broadcast-receiver-not-working