当该应用被杀死时,在Android中运行背景任务的问题
这与问题有关当我几天前发布的应用程序被杀死时,如何在Android中运行背景任务。
阅读了一些博客之后(例如)和代码(电话)我已经完成了一些编码。我的要求是,即使我的应用程序不运行,也要在接收呼叫时向用户展示某种通知(就像Android中的 truecaller 应用程序一样)。我在下面发布代码。
callback_dispatcher.dart
const String HANDLE_INCOMING_CALL_BG = "handleIncomingCallBg";
const String INCOMING_CALL_BG_INITIALIZED = "incomingCallBgInitialized";
const String INCOMING_CALL_BG_INIT_SERVICE = "incomingCallBgInitService";
const String backgroundChannelId = "background_channel";
const String foregroundChannelId = "foreground_channel";
void callback_dispatcher() {
const MethodChannel _backgroundChannel = MethodChannel(backgroundChannelId);
WidgetsFlutterBinding.ensureInitialized();
_backgroundChannel.setMethodCallHandler((MethodCall call) =>
methodCallHandler(call));
_backgroundChannel.invokeMethod<void>(INCOMING_CALL_BG_INITIALIZED);
}
Future<dynamic> methodCallHandler(MethodCall call) async {
if(call.method == HANDLE_INCOMING_CALL_BG) {
final CallbackHandle _handle =
CallbackHandle.fromRawHandle(call.arguments['handle']);
final Function _handlerFunc = PluginUtilities.getCallbackFromHandle(_handle)!;
try {
await _handlerFunc(call.arguments['message']);
} catch(e) {
print('Unable to handle incoming call in background');
print(e);
}
}
return Future<void>.value();
}
void handleBgMsg(String msg) {
debugPrint("[handleBgMsg] incoming call number : " + msg);
// notification to user
}
background_incoming_call.dart
typedef BgMessageHandler(String msg);
class BackgroundIncomingCall {
MethodChannel? foregroundChannel;
Future<void> initialize(BgMessageHandler onBgMessage) async {
foregroundChannel = const MethodChannel(foregroundChannelId);
final CallbackHandle? bgSetupHandle =
PluginUtilities.getCallbackHandle(callback_dispatcher);
final CallbackHandle? bgMsgHandle =
PluginUtilities.getCallbackHandle(onBgMessage);
await foregroundChannel?.invokeMethod<bool>(
INCOMING_CALL_BG_INIT_SERVICE,
<String, dynamic> {
'bgSetupHandle': bgSetupHandle?.toRawHandle(),
'bgMsgHandle': bgMsgHandle?.toRawHandle()
}
);
}
}
in main.dart.dart
我正在初始化 background incommingcall()。 。
在Android部分上,我创建了一个 broadcastreceiver
如下(代码主要来自上述电话 package)。
public class CallEventReceiver extends BroadcastReceiver implements
MethodChannel.MethodCallHandler {
private static final String TAG = "[TEST]";
private static final int NUMBER_LEN = 10;
public static String INCOMING_CALL_BG_INITIALIZED = "incomingCallBgInitialized";
public static String INCOMING_CALL_BG_INIT_SERVICE = "incomingCallBgInitService";
public static String SETUP_HANDLE = "bgSetupHandle";
public static String MESSAGE_HANDLE = "bgMsgHandle";
public static String BG_INCOMING_CALL_CHANNEL_ID = "background_channel";
public static String FG_INCOMING_CALL_CHANNEL_ID = "foreground_channel";
public static String HANDLE_INCOMING_CALL_BG = "handleIncomingCallBg";
public static String SHARED_PREF_NAME = "incomingCallSharedPrefBg";
public static String SHARED_PREF_BG_INCOMING_CALL_HANDLE = "incomingCallSharedPrefBgHandle";
public static String SHARED_PREFS_BACKGROUND_SETUP_HANDLE = "backgroundSetupHandle";
private Activity activity = null;
/* for background isolate*/
private Context appContext = null;
private AtomicBoolean isIsolateRunning = new AtomicBoolean(false);
private List<String> bgIncomingCallQueue = Collections.synchronizedList(new ArrayList<String>());
private MethodChannel bgIncomingCallChannel = null;;
private MethodChannel fgIncomingCallChannel = null;;
private FlutterLoader flutterLoader = null;
private FlutterEngine bgFlutterEngine = null;
private Long bgIncomingCallHandle = null;
/* END */
public CallEventReceiver() {}
public CallEventReceiver(Activity activity) {
super();
this.activity = activity;
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
if(call.method.equals(INCOMING_CALL_BG_INITIALIZED)) {
if(appContext != null) {
onChannelInitialized(appContext);
} else {
throw new RuntimeException("Application context is not set");
}
} else if(call.method.equals(INCOMING_CALL_BG_INIT_SERVICE)) {
if(appContext != null) {
if(call.hasArgument(SETUP_HANDLE) && call.hasArgument(MESSAGE_HANDLE)) {
Long setupHandle = call.<Long>argument(SETUP_HANDLE);
Long msgHandle = call.<Long>argument(MESSAGE_HANDLE);
if (setupHandle == null || msgHandle == null) {
result.error("ILLEGAL_ARGS", "Setup handle or message handle is missing", null);
return;
}
setBgSetupHandle(appContext, setupHandle);
setBgMessageHandle(appContext, msgHandle);
}
} else {
throw new RuntimeException("Application context is not set");
}
} else {
result.notImplemented();
}
}
@Override
public void onReceive(Context context, Intent intent) {
this.appContext = context;
try {
Log.i(TAG, "[CallEventHandler] Receiver start");
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if(state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
if(incomingNumber != null) {
Log.i(TAG, "[CallEventHandler] Incoming number : " + incomingNumber);
if(incomingNumber.length() > NUMBER_LEN) {
incomingNumber = incomingNumber.substring(incomingNumber.length() - NUMBER_LEN, incomingNumber.length());
Log.i(TAG, "[CallEventHandler] Incoming number after : " + incomingNumber);
processIncomingCall(context, incomingNumber);
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void setBgMessageHandle(Context ctx, Long handle) {
bgIncomingCallHandle = handle;
SharedPreferences pref = ctx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
pref.edit().putLong(SHARED_PREF_BG_INCOMING_CALL_HANDLE, handle).apply();
}
public void setBgSetupHandle(Context ctx, Long setupBgHandle) {
SharedPreferences pref = ctx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
pref.edit().putLong(SHARED_PREFS_BACKGROUND_SETUP_HANDLE, setupBgHandle).apply();
}
private void processIncomingCall(Context ctx, String incomingNumber) {
boolean isForeground = isAppForeground(ctx);
Log.i(TAG, "[processIncomingCall] is app in foreground : " + isForeground);
if (isForeground) {
processIncomingCallInForeground(incomingNumber);
} else {
processIncomingCallInBackground(ctx, incomingNumber);
}
}
private void processIncomingCallInBackground(Context ctx, String incomingNumber) {
if(!isIsolateRunning.get()) {
init(ctx);
SharedPreferences sharedPref = ctx.getSharedPreferences(SHARED_PREF_NAME,
Context.MODE_PRIVATE);
Long bgCallbackHandle = sharedPref.getLong(SHARED_PREFS_BACKGROUND_SETUP_HANDLE, 0);
startBackgroundIsolate(ctx, bgCallbackHandle);
bgIncomingCallQueue.add(incomingNumber);
} else {
executeDartCallbackInBgIsolate(ctx, incomingNumber);
}
}
private void processIncomingCallInForeground(String incomingNumber) {
Log.i(TAG, "[processIncomingCallInFg] incoming number : " + incomingNumber);
if(activity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
if(eventSink != null) {
eventSink.success(incomingNumber);
}
}
});
}
}
private void onChannelInitialized(Context ctx) {
isIsolateRunning.set(true);
synchronized(bgIncomingCallQueue) {
Iterator<String> it = bgIncomingCallQueue.iterator();
while(it.hasNext()) {
executeDartCallbackInBgIsolate(ctx, it.next());
}
bgIncomingCallQueue.clear();
}
}
private void init(Context ctx) {
FlutterInjector flutterInjector = FlutterInjector.instance();
flutterLoader = flutterInjector.flutterLoader();
flutterLoader.startInitialization(ctx);
}
private void executeDartCallbackInBgIsolate(Context ctx, String incomingNumber) {
if(bgIncomingCallChannel == null) {
throw new RuntimeException("background channel is not initialized");
}
if(bgIncomingCallHandle == null) {
bgIncomingCallHandle = getBgMessageHandle(ctx);
}
HashMap<String, Object> args = new HashMap<String, Object>();
args.put("handle", bgIncomingCallHandle);
args.put("message", incomingNumber);
bgIncomingCallChannel.invokeMethod(HANDLE_INCOMING_CALL_BG, args);
}
private Long getBgMessageHandle(Context ctx) {
return ctx.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE)
.getLong(SHARED_PREF_BG_INCOMING_CALL_HANDLE, 0);
}
private void startBackgroundIsolate(Context ctx, Long callbackHandle) {
String appBundlePath = flutterLoader.findAppBundlePath();
FlutterCallbackInformation cbInfo = FlutterCallbackInformation.
lookupCallbackInformation(callbackHandle);
DartExecutor.DartCallback dartEntryPoint =
new DartExecutor.DartCallback(ctx.getAssets(), appBundlePath, cbInfo);
bgFlutterEngine = new FlutterEngine(ctx, flutterLoader, new FlutterJNI());
bgFlutterEngine.getDartExecutor().executeDartCallback(dartEntryPoint);
bgIncomingCallChannel = new MethodChannel(bgFlutterEngine.getDartExecutor(),
BG_INCOMING_CALL_CHANNEL_ID);
bgIncomingCallChannel.setMethodCallHandler(this);
}
private boolean isAppForeground(Context ctx) {
KeyguardManager keyGuardManager = (KeyguardManager) ctx.
getSystemService(Context.KEYGUARD_SERVICE);
if(keyGuardManager.isKeyguardLocked()) {
return false;
}
int pid = Process.myPid();
ActivityManager activityManager = (ActivityManager) ctx.
getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> list =
activityManager.getRunningAppProcesses();
for(ActivityManager.RunningAppProcessInfo proc : list) {
if(pid == proc.pid) {
return proc.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
}
}
return false;
}
}
在我的 androidManifest.xml
中,如果我运行我的应用程序并将其最小化,请
<receiver android:name="org.cdot.diu.handler.CallEventReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE"/>
</intent-filter>
</receiver>
立即注册广播接收器, hannebgmsg
已成功地调用。由于当我杀死应用程序时,在终端中没有显示打印或调试消息,因此我使用电话软件包向我发送SMS,该邮件将应用程序最小化时成功发送。但是,如果我杀死了该应用程序,则不会发送SMS。我不确定我在这里做错了什么。我的猜测是,当应用程序被杀死时,广播接收器被杀死。但是,在电话软件包中,没有什么可以表明在杀死应用程序时要保持接收器的特殊护理。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论