diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ClassInvocationStub.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ClassInvocationStub.java
index 1aaf8aa..a5da868 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ClassInvocationStub.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/ClassInvocationStub.java
@@ -50,6 +50,10 @@ public abstract class ClassInvocationStub implements InvocationHandler, IInjectH
@Override
public void injectHook() {
mBase = getWho();
+ // Skip hook if service doesn't exist on this Android version
+ if (mBase == null) {
+ return;
+ }
mProxyInvocation = Proxy.newProxyInstance(mBase.getClass().getClassLoader(), MethodParameterUtils.getAllInterface(mBase.getClass()), this);
if (!onlyProxy) {
inject(mBase, mProxyInvocation);
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/HookManager.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/HookManager.java
index 8651216..67eb09f 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/HookManager.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/hook/HookManager.java
@@ -91,7 +91,7 @@ import top.niunaijun.blackbox.utils.compat.BuildCompat;
import top.niunaijun.blackbox.fake.service.ISettingsProviderProxy;
import top.niunaijun.blackbox.fake.service.FeatureFlagUtilsProxy;
import top.niunaijun.blackbox.fake.service.WorkManagerProxy;
-import top.niunaijun.blackbox.fake.service.IInputMethodManagerProxy;
+// Removed IInputMethodManagerProxy - causes ClassCastException on Android 15
/**
* updated by alex5402 on 3/30/21.
@@ -177,7 +177,7 @@ public class HookManager {
addInjector(new IMediaRouterServiceProxy());
addInjector(new IPowerManagerProxy());
addInjector(new IContextHubServiceProxy());
- addInjector(new IInputMethodManagerProxy());
+ // Removed IInputMethodManagerProxy - causes ClassCastException on Android 15 due to queryLocalInterface returning non-IInterface proxy
addInjector(new IVibratorServiceProxy());
addInjector(new IPersistentDataBlockServiceProxy());
addInjector(AppInstrumentation.get());
diff --git a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/providers/SystemProviderStub.java b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/providers/SystemProviderStub.java
index d71531e..6492d70 100644
--- a/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/providers/SystemProviderStub.java
+++ b/Bcore/src/main/java/top/niunaijun/blackbox/fake/service/context/providers/SystemProviderStub.java
@@ -60,9 +60,12 @@ public class SystemProviderStub extends ClassInvocationStub implements BContentP
if ("call".equals(methodName)) {
// Only fix AttributionSource in call() args, don't replace method name
if (args != null) {
+ Class> attributionSourceClass = BRAttributionSource.getRealClass();
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
- if (arg != null && arg.getClass().getName().equals(BRAttributionSource.getRealClass().getName())) {
+ // Check for null - AttributionSource doesn't exist on Android < S (31)
+ if (arg != null && attributionSourceClass != null &&
+ arg.getClass().getName().equals(attributionSourceClass.getName())) {
ContextCompat.fixAttributionSourceState(arg, BlackBoxCore.getHostUid());
}
}
@@ -79,8 +82,12 @@ public class SystemProviderStub extends ClassInvocationStub implements BContentP
if (!isSystemProviderAuthority(authority)) {
args[0] = BlackBoxCore.getHostPkg();
}
- } else if (arg != null && arg.getClass().getName().equals(BRAttributionSource.getRealClass().getName())) {
- ContextCompat.fixAttributionSourceState(arg, BlackBoxCore.getHostUid());
+ } else if (arg != null) {
+ Class> attrSourceClass = BRAttributionSource.getRealClass();
+ // Check for null - AttributionSource doesn't exist on Android < S (31)
+ if (attrSourceClass != null && arg.getClass().getName().equals(attrSourceClass.getName())) {
+ ContextCompat.fixAttributionSourceState(arg, BlackBoxCore.getHostUid());
+ }
}
}
return method.invoke(mBase, args);
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3fcf9bf..80b647d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -6,6 +6,12 @@
+
+
+
+
+
= android.os.Build.VERSION_CODES.R) {
+ // Android 11+: Need MANAGE_EXTERNAL_STORAGE
if (!android.os.Environment.isExternalStorageManager()) {
Log.w(TAG, "MANAGE_EXTERNAL_STORAGE permission not granted")
showStoragePermissionDialog()
}
+ } else {
+ // Android 10 and below: Need READ/WRITE_EXTERNAL_STORAGE
+ if (androidx.core.content.ContextCompat.checkSelfPermission(
+ this,
+ android.Manifest.permission.WRITE_EXTERNAL_STORAGE
+ ) != android.content.pm.PackageManager.PERMISSION_GRANTED ||
+ androidx.core.content.ContextCompat.checkSelfPermission(
+ this,
+ android.Manifest.permission.READ_EXTERNAL_STORAGE
+ ) != android.content.pm.PackageManager.PERMISSION_GRANTED
+ ) {
+ Log.w(
+ TAG,
+ "Storage permissions not granted on Android ${android.os.Build.VERSION.SDK_INT}"
+ )
+ requestLegacyStoragePermission()
+ }
}
} catch (e: Exception) {
Log.e(TAG, "Error checking storage permission: ${e.message}")
}
}
+ private fun requestLegacyStoragePermission() {
+ try {
+ androidx.core.app.ActivityCompat.requestPermissions(
+ this,
+ arrayOf(
+ android.Manifest.permission.READ_EXTERNAL_STORAGE,
+ android.Manifest.permission.WRITE_EXTERNAL_STORAGE
+ ),
+ STORAGE_PERMISSION_REQUEST_CODE
+ )
+ } catch (e: Exception) {
+ Log.e(TAG, "Error requesting storage permission: ${e.message}")
+ }
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ if (requestCode == STORAGE_PERMISSION_REQUEST_CODE) {
+ if (grantResults.isNotEmpty() &&
+ grantResults.all {
+ it == android.content.pm.PackageManager.PERMISSION_GRANTED
+ }
+ ) {
+ Log.d(TAG, "Storage permissions granted")
+ } else {
+ Log.w(TAG, "Storage permissions denied")
+ }
+ }
+ }
+
private fun showStoragePermissionDialog() {
try {
MaterialDialog(this).show {
diff --git a/build.gradle b/build.gradle
index 9cad877..f42bd9e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -11,7 +11,7 @@ ext {
// targetSdkVersion = 35
minSdk = 21
versionCode = 1
- versionName = "3.0.13-beta2"
+ versionName = "3.1.0-beta"
xVersion = '1.1.0'
hiddenApiBypass = '4.3'
}
\ No newline at end of file