自定义Android系统中设为默认短信App时Realm权限拒绝报错
Realm权限拒绝错误:设为系统默认短信应用时触发Permission denied
开发类短信的系统级默认应用,所有数据通过Realm数据库同步。在自定义Android系统中将该应用设为默认应用后,每次都会抛出如下权限拒绝错误:
RealmError: Permission denied in /Users/jasonflax/Development/realm-java/realm/realm-library/src/main/cpp/io_realm_internal_OsSharedRealm.cpp line 101
应用初始化代码
class App : Application() { override fun onCreate() { super.onCreate() Realm.init(this) val realmConfig = RealmConfiguration.Builder() .compactOnLaunch() .name("sms.realm") .deleteRealmIfMigrationNeeded() .migration(realmMigration) .schemaVersion(QkRealmMigration.SchemaVersion) .build() Realm.setDefaultConfiguration(realmConfig) try { Realm.getDefaultInstance() } catch (e: RealmError){ rebuildRealm(realmConfig) } catch (e: RealmFileException){ rebuildRealm(realmConfig) } } private fun rebuildRealm(realmConfig: RealmConfiguration) { Realm.deleteRealm(realmConfig) Realm.setDefaultConfiguration(realmConfig) } }
崩溃日志
FATAL EXCEPTION: main Process: com.app.sms, PID: 10913 io.realm.exceptions.RealmError: Unrecoverable error. Permission denied in /Users/jasonflax/Development/realm-java/realm/realm-library/src/main/cpp/io_realm_internal_OsSharedRealm.cpp line 101 at io.realm.internal.OsSharedRealm.nativeGetSharedRealm(Native Method) at io.realm.internal.OsSharedRealm.<init>(OsSharedRealm.java:171) at io.realm.internal.OsSharedRealm.getInstance(OsSharedRealm.java:241) at io.realm.BaseRealm.<init>(BaseRealm.java:136) at io.realm.BaseRealm.<init>(BaseRealm.java:103) at io.realm.Realm.<init>(Realm.java:163) at io.realm.Realm.createInstance(Realm.java:499) at io.realm.RealmCache.doCreateRealmOrGetFromCache(RealmCache.java:355) at io.realm.RealmCache.createRealmOrGetFromCache(RealmCache.java:285) at io.realm.Realm.getDefaultInstance(Realm.java:407) at com.app.sms.repository.ConversationRepositoryImpl.getConversations(ConversationRepositoryImpl.kt:58) at com.app.sms.repository.ConversationRepository$DefaultImpls.getConversations$default(ConversationRepository.kt:29) at com.app.sms.feature.main.MainViewModel.<init>(MainViewModel.kt:73) at com.app.sms.feature.main.MainViewModel_Factory.provideInstance(MainViewModel_Factory.java:189) at com.app.sms.feature.main.MainViewModel_Factory.get(MainViewModel_Factory.java:122) at com.app.sms.feature.main.MainViewModel_Factory.get(MainViewModel_Factory.java:28) at com.app.sms.feature.main.MainActivityModule_ProvideMainViewModelFactory.provideInstance(MainActivityModule_ProvideMainViewModelFactory.java:31) at com.app.sms.feature.main.MainActivityModule_ProvideMainViewModelFactory.get(MainActivityModule_ProvideMainViewModelFactory.java:26) at com.app.sms.feature.main.MainActivityModule_ProvideMainViewModelFactory.get(MainActivityModule_ProvideMainViewModelFactory.java:9) at com.app.sms.common.ViewModelFactory.create(ViewModelFactory.kt:28) at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:164) at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:130) at com.app.sms.feature.main.MainActivity$viewModel$2.invoke(MainActivity.kt:152) at com.app.sms.feature.main.MainActivity$viewModel$2.invoke(MainActivity.kt:82) at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74) at com.app.sms.feature.main.MainActivity.getViewModel(Unknown Source:2) at com.app.sms.feature.main.MainActivity.onCreate(MainActivity.kt:177)
问题分析与解决方案
1. 调整Realm存储目录权限
系统默认短信应用的进程上下文可能对默认的getFilesDir()目录存在访问限制,可将Realm文件存储到系统允许的安全目录:
val realmConfig = RealmConfiguration.Builder() .directory(getNoBackupFilesDir()) // 使用系统推荐的无备份目录 .name("sms.realm") .compactOnLaunch() .deleteRealmIfMigrationNeeded() .migration(realmMigration) .schemaVersion(QkRealmMigration.SchemaVersion) .build()
2. 限制Realm仅在主进程初始化
系统默认应用可能被多进程调用(如系统服务触发的进程),导致Realm文件访问冲突。仅在主进程初始化Realm:
override fun onCreate() { super.onCreate() if (packageName == applicationInfo.processName) { // 判断当前是否为主进程 Realm.init(this) val realmConfig = RealmConfiguration.Builder() .name("sms.realm") .compactOnLaunch() .deleteRealmIfMigrationNeeded() .migration(realmMigration) .schemaVersion(QkRealmMigration.SchemaVersion) .build() Realm.setDefaultConfiguration(realmConfig) try { Realm.getDefaultInstance().close() // 初始化后立即关闭实例,避免持有锁 } catch (e: RealmError){ rebuildRealm(realmConfig) } catch (e: RealmFileException){ rebuildRealm(realmConfig) } } }
3. 检查自定义系统的SELinux策略
自定义Android系统的SELinux规则可能严格限制了默认应用的文件访问权限:
- 临时关闭SELinux测试(仅用于排查):
adb shell setenforce 0 - 若问题解决,需联系系统开发者添加SELinux规则,允许应用读写私有目录下的Realm文件。
4. 确保Realm实例正确关闭
所有Realm实例使用后必须关闭,避免资源泄漏导致的文件锁或权限问题。推荐使用use函数自动管理实例生命周期:
fun getConversations(): Flow<List<Conversation>> { return Realm.getDefaultInstance().use { realm -> realm.where(Conversation::class.java) .findAllAsync() .asFlow() .map { it.list } } }
内容的提问来源于stack exchange,提问作者Abdul Hanan
相关产品推荐
相关产品推荐

