java.lang.NullPointerException: 尝试调用虚方法'android.content.pm.PackageManager
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.PackageManager
简介
我是 运行ning flutter v1.17.5 DeviceApps v1.0.10 和 SystemAlertWindow v0.2.2+3(不是最新版本)。而且我想从系统警报 window 打开我的应用程序,即在前台 运行ning,即使应用程序已关闭。
我正在使用 SystemOverlayWindow 插件,该插件是 activity SystemAlertWindowPlugin.java
在我的Application.kt中我注册了插件并通过了注册表
public class Application: FlutterApplication(), PluginRegistrantCallback {
override fun onCreate() {
super.onCreate();
FlutterFirebaseMessagingService.setPluginRegistrant(this);
SystemAlertWindowPlugin.setPluginRegistrant(this);
createNotificationChannels();
FlutterMain.startInitialization(this);
}
override fun registerWith(registry: PluginRegistry?) {
if (!registry!!.hasPlugin("io.flutter.plugins.firebasemessaging")) {
FirebaseMessagingPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"));
}
if (!registry!!.hasPlugin("in.jvapps.system_alert_window")) {
SystemAlertWindowPlugin.registerWith(registry!!.registrarFor("in.jvapps.system_alert_window"));
}
if (!registry!!.hasPlugin("fr.g123k.deviceapps")) {
DeviceAppsPlugin.registerWith(registry!!.registrarFor("fr.g123k.deviceapps"));
}
}
我还注册了另一个名为 DeviceApps 的插件。这是 DeviceAppsPlugin DeviceAppsPlugin.java
问题
简而言之
所以系统覆盖(运行s 在前台)调用 > dart 回调 > 调用 DeviceApps 插件的方法 > 错误发生
长版
我有一个已注册的静态回调 here,当我与系统警报 window 进行点击交互时,它会被调用。但是现在我不想从那个静态回调
在我的飞镖代码中调用 DeviceApps 插件
因此方法通道将调用 this,这将 运行 dart 中定义的静态回调。
这是在后台通道注册和调用的静态dart回调
static Future<void> systemOverlayOnClickListner(String tag) async {
switch (tag) {
case 'button_app_to_foreground':
DeviceApps.openApp('com.companyname.appname'); // this is where I try to run the plugin
await SystemAlertWindow.closeSystemWindow();
break;
}
回调将调用 DeviceApps 插件的方法。这会导致问题,因为 this 方法将尝试从传入它的构造函数的 activity 中获取包管理器。但是根据这个错误 activity 是空的。
E/MethodChannel#g123k/device_apps(24210): Failed to handle method call
E/MethodChannel#g123k/device_apps(24210): java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.PackageManager android.app.Activity.getPackageManager()' on a null object reference
E/MethodChannel#g123k/device_apps(24210): at fr.g123k.deviceapps.DeviceAppsPlugin.openApp(DeviceAppsPlugin.java:141)
因此它将在空对象上调用 getPackageManager()。
activity 只有在从后台通道调用的静态回调中调用时才为 null。但是当我从应用程序范围正常调用它时不是。为什么会这样?
结论
所以总而言之,当我从我的应用程序范围调用插件时,调用插件工作正常。但是一旦通过后台通道的方式调用回调,突然 activity 为空。
我不能只在我的应用程序中启动一个隔离,然后从我的回调中向它发送一条消息,就像它的完成方式一样 here。因为我需要此代码在应用程序关闭时工作,并且应用程序范围的隔离不会在后台 运行。
那么如何从回调中打开我的应用程序?
这是完整的堆栈跟踪
E/flutter (26735): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: PlatformException(error, Attempt to invoke virtual method 'android.content.pm.PackageManager android.app.Activity.getPackageManager()' on a null object reference, null)
E/flutter (26735): #0 StandardMethodCodec.decodeEnvelope
package:flutter/…/services/message_codecs.dart:569
E/flutter (26735): #1 MethodChannel._invokeMethod
package:flutter/…/services/platform_channel.dart:156
E/flutter (26735): <asynchronous suspension>
E/flutter (26735): #2 MethodChannel.invokeMethod
package:flutter/…/services/platform_channel.dart:329
E/flutter (26735): #3 DeviceApps.openApp
package:device_apps/device_apps.dart:81
E/flutter (26735): #4 SystemOverlayController.systemOverlayOnClickListner
package:appname/…/singletons/system_overlay_controller.dart:51
E/flutter (26735): #5 callbackDispatcher.<anonymous closure>
package:system_alert_window/system_alert_window.dart:136
E/flutter (26735): #6 MethodChannel._handleAsMethodCall
package:flutter/…/services/platform_channel.dart:409
E/flutter (26735): #7 MethodChannel.setMethodCallHandler.<anonymous closure>
package:flutter/…/services/platform_channel.dart:377
E/flutter (26735): #8 _DefaultBinaryMessenger.handlePlatformMessage
package:flutter/…/services/binding.dart:199
E/flutter (26735): #9 _invoke3.<anonymous closure> (dart:ui/hooks.dart:290:15)
E/flutter (26735): #10 _rootRun (dart:async/zone.dart:1184:13)
E/flutter (26735): #11 _CustomZone.run (dart:async/zone.dart:1077:19)
E/flutter (26735): #12 _CustomZone.runGuarded (dart:async/zone.dart:979:7)
E/flutter (26735): #13 _invoke3 (dart:ui/hooks.dart:289:10)
E/flutter (26735): #14 _dispatchPlatformMessage (dart:ui/hooks.dart:164:5
示例回购
我什至尝试将打开应用程序方法直接添加到 forked 版本的系统警报 window。并将其实现到一个示例回购中,您可以在此处找到,采用名为 my-branch 的分支。
https://github.com/michael-ottink/system_overlay_callback_null_activity
但它抛出完全相同的错误。即使我使用完全相同的activity。所以我觉得跟背景频道有关系。
运行 应用程序,然后单击按钮以获取叠加层。将应用程序带到后台,然后单击叠加层中的打开。发生错误。
额外信息
我认为 是一个类似的问题,只是他们选择不注册插件,因为它只是前台。在我的例子中,我想分叉这些插件中的任何一个并修改它们,以便它也可以在后台运行。我该怎么做?
我在 https://github.com/fmatosqg/system_alert_window/tree/hack_fix
找到了修复崩溃症状的 hack
简而言之,插件在不再可用时访问 activity。我的快速修复存储 activity.applicationContext
(保证在应用程序运行时存在 - 即使它只是一个覆盖层)并将其存储在一个静态变量中,该变量可能比 class SystemAlertWindowPlugin
中的对象长寿.
. . .
private static Context staticContext;
. . .
private boolean openApp(String packageName) {
Intent launchIntent = staticContext.getPackageManager().getLaunchIntentForPackage(packageName);
if (launchIntent != null) {
// null pointer check in case package name was not found
staticContext.startActivity(launchIntent);
return true;
}
return false;
}
我想解释一下为什么这不是一个正确的解决方法,但我现在时间不够,稍后会尝试回来说明原因。但我不是 flutter 插件方面的专家,如果不花更多时间了解插件本身,我将无法确定正确的代码,我可能做不到。
我在另一个插件上做了一个非常相似的修复和非常相似的崩溃,我希望它能帮助指导你或插件作者:https://github.com/hnvn/flutter_image_cropper/pull/167
最后,一些建议。 Android 版本之间变化很大,我强烈建议您在模拟器 运行 android 10 和 11 上尝试这个和其他修复,因为它们对开展活动。我知道背景的变化,但我不是所有细节的最新信息,或者如果从覆盖启动构成前景或背景 ANDROID 目的。尝一尝:https://www.reddit.com/r/androiddev/comments/dcleem/android_10_restricts_how_to_start_activity_from/
简介
我是 运行ning flutter v1.17.5 DeviceApps v1.0.10 和 SystemAlertWindow v0.2.2+3(不是最新版本)。而且我想从系统警报 window 打开我的应用程序,即在前台 运行ning,即使应用程序已关闭。
我正在使用 SystemOverlayWindow 插件,该插件是 activity SystemAlertWindowPlugin.java
在我的Application.kt中我注册了插件并通过了注册表
public class Application: FlutterApplication(), PluginRegistrantCallback {
override fun onCreate() {
super.onCreate();
FlutterFirebaseMessagingService.setPluginRegistrant(this);
SystemAlertWindowPlugin.setPluginRegistrant(this);
createNotificationChannels();
FlutterMain.startInitialization(this);
}
override fun registerWith(registry: PluginRegistry?) {
if (!registry!!.hasPlugin("io.flutter.plugins.firebasemessaging")) {
FirebaseMessagingPlugin.registerWith(registry!!.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"));
}
if (!registry!!.hasPlugin("in.jvapps.system_alert_window")) {
SystemAlertWindowPlugin.registerWith(registry!!.registrarFor("in.jvapps.system_alert_window"));
}
if (!registry!!.hasPlugin("fr.g123k.deviceapps")) {
DeviceAppsPlugin.registerWith(registry!!.registrarFor("fr.g123k.deviceapps"));
}
}
我还注册了另一个名为 DeviceApps 的插件。这是 DeviceAppsPlugin DeviceAppsPlugin.java
问题
简而言之
所以系统覆盖(运行s 在前台)调用 > dart 回调 > 调用 DeviceApps 插件的方法 > 错误发生
长版
我有一个已注册的静态回调 here,当我与系统警报 window 进行点击交互时,它会被调用。但是现在我不想从那个静态回调
在我的飞镖代码中调用 DeviceApps 插件因此方法通道将调用 this,这将 运行 dart 中定义的静态回调。
这是在后台通道注册和调用的静态dart回调
static Future<void> systemOverlayOnClickListner(String tag) async {
switch (tag) {
case 'button_app_to_foreground':
DeviceApps.openApp('com.companyname.appname'); // this is where I try to run the plugin
await SystemAlertWindow.closeSystemWindow();
break;
}
回调将调用 DeviceApps 插件的方法。这会导致问题,因为 this 方法将尝试从传入它的构造函数的 activity 中获取包管理器。但是根据这个错误 activity 是空的。
E/MethodChannel#g123k/device_apps(24210): Failed to handle method call
E/MethodChannel#g123k/device_apps(24210): java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.PackageManager android.app.Activity.getPackageManager()' on a null object reference
E/MethodChannel#g123k/device_apps(24210): at fr.g123k.deviceapps.DeviceAppsPlugin.openApp(DeviceAppsPlugin.java:141)
因此它将在空对象上调用 getPackageManager()。
activity 只有在从后台通道调用的静态回调中调用时才为 null。但是当我从应用程序范围正常调用它时不是。为什么会这样?
结论
所以总而言之,当我从我的应用程序范围调用插件时,调用插件工作正常。但是一旦通过后台通道的方式调用回调,突然 activity 为空。
我不能只在我的应用程序中启动一个隔离,然后从我的回调中向它发送一条消息,就像它的完成方式一样 here。因为我需要此代码在应用程序关闭时工作,并且应用程序范围的隔离不会在后台 运行。
那么如何从回调中打开我的应用程序?
这是完整的堆栈跟踪
E/flutter (26735): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: PlatformException(error, Attempt to invoke virtual method 'android.content.pm.PackageManager android.app.Activity.getPackageManager()' on a null object reference, null)
E/flutter (26735): #0 StandardMethodCodec.decodeEnvelope
package:flutter/…/services/message_codecs.dart:569
E/flutter (26735): #1 MethodChannel._invokeMethod
package:flutter/…/services/platform_channel.dart:156
E/flutter (26735): <asynchronous suspension>
E/flutter (26735): #2 MethodChannel.invokeMethod
package:flutter/…/services/platform_channel.dart:329
E/flutter (26735): #3 DeviceApps.openApp
package:device_apps/device_apps.dart:81
E/flutter (26735): #4 SystemOverlayController.systemOverlayOnClickListner
package:appname/…/singletons/system_overlay_controller.dart:51
E/flutter (26735): #5 callbackDispatcher.<anonymous closure>
package:system_alert_window/system_alert_window.dart:136
E/flutter (26735): #6 MethodChannel._handleAsMethodCall
package:flutter/…/services/platform_channel.dart:409
E/flutter (26735): #7 MethodChannel.setMethodCallHandler.<anonymous closure>
package:flutter/…/services/platform_channel.dart:377
E/flutter (26735): #8 _DefaultBinaryMessenger.handlePlatformMessage
package:flutter/…/services/binding.dart:199
E/flutter (26735): #9 _invoke3.<anonymous closure> (dart:ui/hooks.dart:290:15)
E/flutter (26735): #10 _rootRun (dart:async/zone.dart:1184:13)
E/flutter (26735): #11 _CustomZone.run (dart:async/zone.dart:1077:19)
E/flutter (26735): #12 _CustomZone.runGuarded (dart:async/zone.dart:979:7)
E/flutter (26735): #13 _invoke3 (dart:ui/hooks.dart:289:10)
E/flutter (26735): #14 _dispatchPlatformMessage (dart:ui/hooks.dart:164:5
示例回购
我什至尝试将打开应用程序方法直接添加到 forked 版本的系统警报 window。并将其实现到一个示例回购中,您可以在此处找到,采用名为 my-branch 的分支。
https://github.com/michael-ottink/system_overlay_callback_null_activity
但它抛出完全相同的错误。即使我使用完全相同的activity。所以我觉得跟背景频道有关系。
运行 应用程序,然后单击按钮以获取叠加层。将应用程序带到后台,然后单击叠加层中的打开。发生错误。
额外信息
我认为
我在 https://github.com/fmatosqg/system_alert_window/tree/hack_fix
找到了修复崩溃症状的 hack简而言之,插件在不再可用时访问 activity。我的快速修复存储 activity.applicationContext
(保证在应用程序运行时存在 - 即使它只是一个覆盖层)并将其存储在一个静态变量中,该变量可能比 class SystemAlertWindowPlugin
中的对象长寿.
. . .
private static Context staticContext;
. . .
private boolean openApp(String packageName) {
Intent launchIntent = staticContext.getPackageManager().getLaunchIntentForPackage(packageName);
if (launchIntent != null) {
// null pointer check in case package name was not found
staticContext.startActivity(launchIntent);
return true;
}
return false;
}
我想解释一下为什么这不是一个正确的解决方法,但我现在时间不够,稍后会尝试回来说明原因。但我不是 flutter 插件方面的专家,如果不花更多时间了解插件本身,我将无法确定正确的代码,我可能做不到。
我在另一个插件上做了一个非常相似的修复和非常相似的崩溃,我希望它能帮助指导你或插件作者:https://github.com/hnvn/flutter_image_cropper/pull/167
最后,一些建议。 Android 版本之间变化很大,我强烈建议您在模拟器 运行 android 10 和 11 上尝试这个和其他修复,因为它们对开展活动。我知道背景的变化,但我不是所有细节的最新信息,或者如果从覆盖启动构成前景或背景 ANDROID 目的。尝一尝:https://www.reddit.com/r/androiddev/comments/dcleem/android_10_restricts_how_to_start_activity_from/