Closed zhaodice closed 2 years ago
APP端的登录代码
runBlocking(MiraiConsole.coroutineContext) {
loginBot?.closeAndJoin()
loginBot = BotFactory.newBot(qq.toLong(), password) {
...
插件端的登录代码:
....
BotFactory.newBot
....
看起来像是缺依赖导致 IMirai 没加载上
看起来像是缺依赖导致 IMirai 没加载上
如果是缺依赖,为什么在插件内调用登录却一切正常呢?
问题就诡异在,插件内调用登录一切正常,插件外调用(也就是mirai本体环境)却空指针错误
问题就诡异在,插件内调用登录一切正常,插件外调用(也就是mirai本体环境)却空指针错误
你在安卓APP 里内嵌了一个 Mirai-Console ?
问题就诡异在,插件内调用登录一切正常,插件外调用(也就是mirai本体环境)却空指针错误
你在安卓APP 里内嵌了一个 Mirai-Console ?
没错,我在console之外(mirai环境)调用登录就出错,但在console内(插件环境内,也就是onEnable那个地方)调用登录就正常
其实APP的整体结构和MiraiAndroid
差不多
这个问题是在2.10-RC的时候就开始出现的,2.9.0-RC2以及之前的版本一切正常
2.10 应该没有改这个加载策略
顺带一提,我的console版本依然是2.6.0
,但我觉得关系应该不是很大,因为console原则上不应该影响core的api(况且在console插件内调用登录还是正常的)
有无稍微详细点的错误堆栈
你使用的 kotlin-gradle 版本为?
提供 build.gradle
有无稍微详细点的错误堆栈
堆栈,这个...我再看一下,当时没保存...,但我确定是在调用 BotFactory.newBot 的时候出的问题(你们顺着这个入口进去追溯一下应该知道在怎么地方调用了IMirai?) kotlin的依赖我引入了这些包
2022/01/29 22:27 3,038,560 kotlin-reflect-1.6.10.jar
2022/01/29 22:28 1,508,076 kotlin-stdlib-1.6.10.jar
2022/01/29 22:28 1,488,107 kotlinx-coroutines-core-jvm-1.6.0.jar
2021/11/22 19:12 17,709 kotlinx-coroutines-io-0.1.16.jar
2021/11/22 19:12 421,729 kotlinx-coroutines-io-jvm-0.1.16.jar
2022/01/29 22:29 342,172 kotlinx-serialization-core-jvm-1.3.2.jar
2022/01/29 22:29 212,236 kotlinx-serialization-json-jvm-1.3.2.jar
2022/01/29 22:30 94,493 kotlinx-serialization-protobuf-jvm-1.3.2.jar
然后是build.gradle(其实没有意义,因为我直接使用kotlin库的jar文件)
buildscript {
ext {
//Mirai 2.7+
kotlin_version = '1.6.0'
kotlin_coroutines_version = '1.6.0'
kotlinx_serialization_version = '1.2.1'
androidx_lifecycle_version = '2.3.1'
androidx_navigation_version = '2.3.5'
}
...
提供完整的 build.gradle,你觉得没用的信息可能我觉得有用
这是app下的build.gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 30
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = ['-Xjvm-default=all','-Xopt-in=kotlin.RequiresOptIn']
}
defaultConfig {
multiDexEnabled true
minSdkVersion 21
versionCode 10
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
flavorDimensions "versionCode"
externalNativeBuild {
cmake {
//cppFlags "-std=c++11 -fexceptions -pthread"
/**
* -DHAVE_CONFIG_H这个有个坑 lame配置这个参数编译不通过 libmad不加这个参数转码会失真
*/
cFlags "-DSTDC_HEADERS -DHAVE_CONFIG_H -DFPM_DEFAULT"
}
ndk {
}
}
}
buildTypes {
release {
zipAlignEnabled true
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
packagingOptions {
exclude "META-INF/**"
exclude "WEB-INF/**"
exclude "okhttp3/**"
exclude "net/**"
exclude "org/**"
exclude 'DebugProbesKt.bin'
merge 'org/mozilla/javascript/resources/Messages.properties'
}
productFlavors {
miraiCore {
applicationId "org.mirai.zhao.dice"
versionName "4.3.7"
targetSdkVersion 29//改成30将无法访问/sdcard根目录!
resValue "string", "app_name", "DICE X4"
manifestPlaceholders = [
FRAME_TYPE : "MiraiCore"
]
ndk {
abiFilters "armeabi-v7a", "arm64-v8a"
}
}
miraiGo {
applicationId "org.mirai.zhao.gdice"
versionName "4.0.4"
targetSdkVersion 29
resValue "string", "app_name", "GDICE X4"
manifestPlaceholders = [
FRAME_TYPE : "MiraiGo"
]
ndk {
abiFilters "arm64-v8a","armeabi-v7a"
}
}
}
applicationVariants.all { variant ->
variant.outputs.all { output ->
def outputFile = output.outputFile
def fileName = "Dice_unknown"
def appName = "unknown"
if (outputFile != null && outputFile.name.endsWith('.apk')) {
if (productFlavors.applicationId[0] == 'org.mirai.zhao.gdice') {
appName = "GDice"
}else if (productFlavors.applicationId[0] == 'org.mirai.zhao.dice') {
appName = "Dice"
}
if (variant.buildType.name == 'release') {//如果是release包
fileName = "${appName}_release_v${productFlavors.versionName[0]}.apk"
} else if (variant.buildType.name == 'debug') {//如果是debug包
fileName = "${appName}_debug_v${productFlavors.versionName[0]}.apk"
}
// 自定义输出路径
//variant.getPackageApplicationProvider().get().outputDirectory = new File(project.rootDir.absolutePath + File.separator + "/build/release")
outputFileName = fileName
}
}
}
}
repositories {
maven { url 'https://jitpack.io' }
}
//
configurations {
cleanedAnnotations
implementation.exclude group: 'org.jetbrains', module:'annotations'
implementation.exclude group: 'org.jetbrains.kotlinx', module:'kotlinx-coroutines-core-jvm'
implementation.exclude group: 'org.jetbrains.kotlin', module:'kotlin-stdlib'
}
kotlin.sourceSets.all {
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.console.ConsoleFrontEndImplementation")
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.console.util.ConsoleInternalApi")
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.console.util.ConsoleExperimentalApi")
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalApi")
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiExperimentalApi")
}
dependencies {
implementation (fileTree(dir: "libs", include: ["*.jar"]))
implementation (fileTree(dir: "../allLibs/ext", include: ["ext-gson-*.jar",
"ext-luaj-*.jar",
"ext-snakeyaml-*.jar",
"ext-toml4j-*.jar"]))
implementation (fileTree(dir: "../allLibs/kotlin", include: ["*.jar"]))
try{
miraiCoreImplementation (fileTree(dir: "../allLibs/miraiConsole", include: ["*.jar"]))
miraiCoreImplementation (fileTree(dir: "../allLibs/miraiLibs", include: ["*.jar"]))
}catch(Throwable ignored){
}
try{
miraiGoImplementation "com.koushikdutta.async:androidasync:3.1.0"
//miraiGoImplementation project(":miraigo-zhao") //动态dex加载
}catch(Throwable ignored){
}
//implementation project(':lib_permisshelper')
implementation 'org.greenrobot:eventbus:3.0.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'io.apisense:rhino-android:1.1.1'
implementation 'androidx.annotation:annotation:1.2.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$androidx_lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$androidx_lifecycle_version"
implementation "androidx.navigation:navigation-fragment-ktx:$androidx_navigation_version"
implementation "androidx.navigation:navigation-ui-ktx:$androidx_navigation_version"
implementation 'cat.ereza:customactivityoncrash:1.3.0'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
}
这是主项目的gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext {
//Mirai 2.7+
kotlin_version = '1.6.0'
kotlin_coroutines_version = '1.6.0'
kotlinx_serialization_version = '1.2.1'
androidx_lifecycle_version = '2.3.1'
androidx_navigation_version = '2.3.5'
}
repositories {
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/public' }
//mavenCentral()
//google()
//jcenter()
}
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:6.1.0'
classpath 'com.android.tools.build:gradle:7.0.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.0"//不得轻易升级,影响兼容性!!
//classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/public' }
maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
//google()
//jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
其中allLibs文件夹下的文件结构
─ext
│ ext-gson-2.8.8.jar
│ ext-json-20160810.jar
│ ext-luaj-3.0.1.jar
│ ext-snakeyaml-1.26.jar
│
├─kotlin
│ kotlin-reflect-1.6.10.jar
│ kotlin-stdlib-1.6.10.jar
│ kotlinx-coroutines-core-jvm-1.6.0.jar
│ kotlinx-coroutines-io-0.1.16.jar
│ kotlinx-coroutines-io-jvm-0.1.16.jar
│ kotlinx-serialization-core-jvm-1.3.2.jar
│ kotlinx-serialization-json-jvm-1.3.2.jar
│ kotlinx-serialization-protobuf-jvm-1.3.2.jar
│
├─miraiConsole
│ mirai-CheckerConstants.jar
│ mirai-console-2.6.0-dalvik.jar
│ mirai-yamlkt-jvm-0.7.5.jar
│
└─miraiLibs
mirai-core-android-2.9.0-RC2.jar
mirai-core-api-android-2.9.0-RC2.jar
mirai-core-utils-android-2.9.0-RC2.jar
mirai-dependents.jar
不要通过 fileTree 添加 jar 依赖,这很有可能就是问题原因
不要通过 fileTree 添加 jar 依赖,这很有可能就是问题原因
主要是,我觉得我的开发制程...没有那么标准,为简化问题便没直接贴出来,见笑了 之前一直这样用的,都是正常的,这次就失灵了...明天我再试试看用implementation 引用包试试看吧(主要是这个强国总是干扰我同步,所以才直接用jar出此下策)
不要通过 fileTree 添加 jar 依赖,这很有可能就是问题原因
好像没有用,我直接 implementation("net.mamoe:mirai-core:2.10.0") 之后 一样是空指针错误,我稍后贴出详细错误堆栈
错误信息
java.lang.NullPointerException: Attempt to invoke interface method 'net.mamoe.mirai.BotFactory net.mamoe.mirai.lMirai.getBotFactory()' on a null object reference
at net.mamoe.mirai.BotFactory$INSTANCE.newBot()
at org.mirai.zhao.dice.console.MiraiCoreConsoleService$iConsoleServiceStub$1$loginBot$1$1.invokeSuspend()
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith()
at kotlinx.coroutines.DispatchedTask.run()
at kotlinx.coroutines.EventLooplmplBase.processNextEvent()
at kotlinx.coroutines.BlockingCoroutine.joinBlocking()
at kotlinx.coroutines.BuildersKt_ BuildersKt.runBlocking()
at kotlinx.coroutines.BuildersKt.runBlocking()
at kotlinx.coroutines. BuildersKt_ BuildersKt.runBlocking$default()
图片版本(走的图片识别,文字版本可能有错别字?):
之前都是好好的,Mirai2.10.0-RC就开始不行了,不太清楚这个版本更新了什么东西导致的
解决了,我跟着错误信息找到了相关源码文件 https://github.com/mamoe/mirai/blob/7a32afc14c59618a726da68c957ec7d237224fde/mirai-core-api/src/commonMain/kotlin/IMirai.kt 发现了提示,我在初始化的时候调用了
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") // 必要
net.mamoe.mirai._MiraiInstance.set(net.mamoe.mirai.internal.MiraiImpl())
问题解决,虽然还是不知道这是为什么,之前版本明明不需要的,为什么2.10-RC就要这样(如果这是新版本无关紧要的问题的话就可以close了)
提供能复现错误的最终 jar & apk 成品,可能是因为 proguard
提供能复现错误的最终 jar & apk 成品,可能是因为 proguard
但是,当时测试,我加了一句这个
-keep class ** { *; }
(我没法把混淆关掉,因为关掉了会出现其他未知错误,总之我这边编译环境乱糟糟的)
我看了代码,基于 Kotlin null 检查,上述 NPE 绝对不可能出现。怀疑是 ProGuard 优化字节码导致改变了行为。总之你那边构建环境太复杂了,我也不好分析。
我看了代码,基于 Kotlin null 检查,上述 NPE 绝对不可能出现。怀疑是 ProGuard 优化字节码导致改变了行为。总之你那边构建环境太复杂了,我也不好分析。
说到 Kotlin null 检查,可能是因为这个地方吧?总之问题解决就好了
#去掉空检查
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
static void checkNotNull(...);
static void checkParameterIsNotNull(...);
static void checkNotNullExpressionValue(...);
static void checkNotNullParameter(...);
static void checkExpressionValueIsNotNull(...);
static void throwUninitializedPropertyAccessException(...);
}
题外话:为什么要去掉 null 检查?这是 fail-fast 行为而且这些检查速度很快
.class public final Lnet/mamoe/mirai/_MiraiInstance;
.super Ljava/lang/Object;
.source ""
.method public static final get()Lnet/mamoe/mirai/IMirai;
.locals 1
.annotation runtime Lkotlin/jvm/JvmStatic;
.end annotation
.annotation build Lorg/jetbrains/annotations/NotNull;
.end annotation
sget-object v0, Lnet/mamoe/mirai/_MiraiInstance;->instance:Lnet/mamoe/mirai/IMirai;
if-nez v0, :cond_0
- invoke-static {}, Lnet/mamoe/mirai/FindMiraiInstance_androidKt;->findMiraiInstance()Lnet/mamoe/mirai/IMirai;
move-result-object v0
sput-object v0, Lnet/mamoe/mirai/_MiraiInstance;->instance:Lnet/mamoe/mirai/IMirai;
:cond_0
return-object v0
.end method
.class public final Lnet/mamoe/mirai/FindMiraiInstance_androidKt;
.super Ljava/lang/Object;
.source ""
# direct methods
.method public static final synthetic findMiraiInstance()Lnet/mamoe/mirai/IMirai;
.locals 2
const-class v0, Lnet/mamoe/mirai/IMirai;
invoke-static {v0}, Ljava/util/ServiceLoader;->load(Ljava/lang/Class;)Ljava/util/ServiceLoader;
move-result-object v0
invoke-static {v0}, Lkotlin/collections/CollectionsKt;->firstOrNull(Ljava/lang/Iterable;)Ljava/lang/Object;
move-result-object v0
check-cast v0, Lnet/mamoe/mirai/IMirai;
if-nez v0, :cond_0
const-class v0, Lnet/mamoe/mirai/internal/MiraiImpl;
sget-object v1, Lnet/mamoe/mirai/internal/MiraiImpl;->INSTANCE:Lnet/mamoe/mirai/internal/MiraiImpl$INSTANCE;
invoke-static {v0}, Lkotlin/jvm/JvmClassMappingKt;->getKotlinClass(Ljava/lang/Class;)Lkotlin/reflect/KClass;
move-result-object v0
invoke-static {v0}, Lkotlin/reflect/full/KClasses;->getCompanionObjectInstance(Lkotlin/reflect/KClass;)Ljava/lang/Object;
move-result-object v0
check-cast v0, Lnet/mamoe/mirai/IMirai;
:cond_0
return-object v0
.end method
经过最终路由追踪确定原因为 ProGuard 祛除了 MiraiImpl
的相关 kotlin 注解, 导致 KClass<*>.companionObjectInstance
返回 null, 并且因为祛除了空检查导致没有在请求服务的时候直接报错
这个应该算是 ProGuard 的 bug
我是在安卓平台上编译运行的mirai 非常诡异的错误,在
Mirai2.9.0-RC2
上是正常的,但更新到Mirai2.10.0-RC2
的时候,在app端调用BotFactory
就会出现这种错误,但更诡异的是,在插件内调用BotFactory
进行登录则一切正常,问题可能出在哪里呢? 错误信息:java.lang.NullPointerException: Attempt to invoke interface method 'net.mamoe.mirai.BotFactory net.mamoe.mirai.IMirai.getBotFactory()' on a null object reference