C/C++ 在通过 Android NDK 的 JNI 中无法访问 Java 方法

12 浏览
0 Comments

C/C++ 在通过 Android NDK 的 JNI 中无法访问 Java 方法

我正在尝试从使用NDK构建的C类文件中调用Java方法。

它经常抛出常见的“找不到非静态方法”错误,并使整个Android应用程序崩溃。

以下是代码片段(可能不需要一些东西,但是我将它们保持原样,因为重点/问题在于refreshJNIIntegration()方法,而不是代码的格式)。

Java类:

@Keep
@RequiresApi(api = Build.VERSION_CODES.DONUT)
public class MainActivity extends AppCompatActivity {
    public native String getHealthStatus(String stringValue, String packageName);
    @SuppressLint("SourceLockedOrientationActivity")
    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(BuildConfig.FLAVOR.endsWith("")) {
            if (Build.SUPPORTED_ABIS[0].equals("armeabi-v7a") || (Build.SUPPORTED_ABIS[0].equals("arm64-v8a"))) {
                System.loadLibrary("integration");
            }
        }
    }
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        try {
            super.onActivityResult(requestCode, resultCode, data);
            if (requestCode == RC_SIGN_IN) {
                Task task = GoogleSignIn.getSignedInAccountFromIntent(data);
                GoogleSignInAccount account = task.getResult(ApiException.class);
                if (account!=null) {
                    if (BuildConfig.FLAVOR.endsWith("")) {
                        try {
                            if (integrationAvailable) {
                                if (mGSIA==null) mGSIA = account;
                                final String ProStatusHealth = getHealthStatus(account.getEmail(), getApplicationContext().getPackageName());
                            }
                        }
                    }
                }
            }
        }
    }
    public String refreshJNIIntegration(String version) {
        return String.valueOf(getFilesDir());
    }
}

C类(最初从Java调用,然后调用下面的方法)在integraton.c文件中:

#ifdef __cplusplus
extern "C" {
#endif
    JNIEXPORT jstring JNICALL
    Java_com_linardsl_libhacontimig_MainActivity_getHealthStatus(JNIEnv *env, jobject instance, jstring stringValue_, jstring packageName_) {
        jstring apppath = Java_com_linardsl_libhacontimig_MainActivity_setJNIInterface(env, instance, "", "");
}
#ifdef __cplusplus
}
#endif

C类(发生错误和崩溃的地方)在integration.c文件中:

#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jstring JNICALL
Java_com_linardsl_libhacontimig_MainActivity_setJNIInterface(JNIEnv *env, jobject instance,
                                                             jstring stringValue_, jstring packageName_) {
    jstring jstr = (*env)->NewStringUTF(env, LIB_VERS);
    // Does not work: jclass clazz = (*env)->FindClass(env,"com/linardsl/libhacontimig/MainActivity");
    jclass clazz = (*env)->GetObjectClass(env, instance);
    jmethodID messageMe = (*env)->GetMethodID(env, clazz, "refreshJNIIntegration",
                                              "(Ljava/lang/String;)Ljava/lang/String;");
    // Does not work: jmethodID messageMe = (*env)->GetMethodID(env, clazz, "refreshJNIIntegration", "(Ljava/lang/String;)V");
    jobject result = (*env)->CallObjectMethod(env, instance, messageMe, jstr);
    const char* str = (*env)->GetStringUTFChars(env, (jstring) result, NULL);
    (*env)->ReleaseStringUTFChars(env, jstr, str);
    return (*env)->NewStringUTF(env, str);
}
#ifdef __cplusplus
}
#endif

build.gradle文件:

/*

* Copyright (c) Linards Liepiņš, Riga, Latvia, 19-2022. All rights reserved.

*/

import org.apache.tools.ant.taskdefs.condition.Os

// android

apply plugin: 'com.android.application'

// junit

apply plugin: 'de.mannodermaus.android-junit5'

// google

apply plugin: 'com.google.gms.google-services'

// Apply the Crashlytics Gradle plugin

apply plugin: 'com.google.firebase.crashlytics'

// Apply the Performance Monitoring plugin

apply plugin: 'com.google.firebase.firebase-perf'

// huawei

apply plugin: 'com.huawei.agconnect'

android {

signingConfigs {

release {

v2SigningEnabled true

if (Os.isFamily(Os.FAMILY_WINDOWS)) {

storeFile file(System.getProperty("user.home")+"\\keystore.jks")

storePassword ''

keyPassword ''

keyAlias = ''

} else if (Os.isFamily(Os.FAMILY_UNIX)) {

printf("Signing not supported in *Nix (Linux) OS environment. Yet. ")

} else if (Os.isFamily(Os.FAMILY_MAC)) {

printf("Signing not supported in Mac OS environment. Yet. ")

}

}

}

compileSdkVersion 33

buildToolsVersion "33.0.0"

ndkVersion '25.1.8937393'

defaultConfig {

applicationId "com.linardsl.libhacontimig"

minSdkVersion 26

targetSdkVersion 33

versionCode 40

versionName "0.3.1"

multiDexEnabled true

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

if (Os.isFamily(Os.FAMILY_WINDOWS)) {

signingConfig signingConfigs.release

}

ndk {

// Source(s): https://stackoverflow.com/questions/63373245/how-to-add-debug-symbols-to-build-gradle

debugSymbolLevel 'FULL'

abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'

}

resConfigs 'en', 'fr', 'ru', 'lv', 'in', 'es'

}

flavorDimensions "version"

productFlavors {

alpha {

dimension "version"

applicationIdSuffix ".alpha"

versionNameSuffix "-alpha"

buildConfigField "boolean", "IS_BLEEDING", "true"

resValue 'string', 'app_name', ""

}

alphaPro {

dimension "version"

applicationIdSuffix ".alphaPro"

versionNameSuffix "-alphaPro"

buildConfigField "boolean", "IS_BLEEDING", "true"

resValue 'string', 'app_name', ""

}

beta {

dimension "version"

applicationIdSuffix ".beta"

versionNameSuffix "-beta"

buildConfigField "boolean", "IS_BLEEDING", "true"

resValue 'string', 'app_name', ""

}

betaPro {

dimension "version"

applicationIdSuffix ".betaPro"

versionNameSuffix "-betaPro"

buildConfigField "boolean", "IS_BLEEDING", "true"

resValue 'string', 'app_name', ""

}

demo {

dimension "version"

applicationIdSuffix ".demo"

versionNameSuffix "-demo"

buildConfigField "boolean", "IS_BLEEDING", "false"

resValue 'string', 'app_name', ""

}

production {

dimension "version"

applicationIdSuffix ".final"

versionNameSuffix "-final"

buildConfigField "boolean", "IS_BLEEDING", "false"

resValue 'string', 'app_name', ""

if (Os.isFamily(Os.FAMILY_WINDOWS)) {

signingConfig signingConfigs.release

}

}

}

externalNativeBuild {

ndkBuild {

path "src/main/jni/Android.mk"

}

}

buildTypes {

debug {

minifyEnabled true

shrinkResources true

testCoverageEnabled = true

jniDebuggable true

}

release {

minifyEnabled true

testCoverageEnabled = false

debuggable false

proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

if (Os.isFamily(Os.FAMILY_WINDOWS)) {

signingConfig signingConfigs.release

}

zipAlignEnabled true

firebaseCrashlytics {

nativeSymbolUploadEnabled true

}

}

}

// Fix for > com.android.builder.errors.EvalIssueException: The option 'android.enablePrefab' is deprecated. It was removed in version 4.1 of the Android Gradle plugin.

// Fix for > https://stackoverflow.com/questions/45279479/error-could-not-parse-the-android-application-modules-gradle-config

buildFeatures {

prefab true

viewBinding true

}

// Fix for https://stackoverflow.com/questions/67672583/jni-detected-error-in-application-java-lang-unsatisfiedlinkerror-couldnt-find

packagingOptions {

jniLibs {

useLegacyPackaging = true

}

}

// Fix for https://stackoverflow.com/questions/49891730/invoke-customs-are-only-supported-starting-with-android-0-min-api-26

compileOptions {

sourceCompatibility JavaVersion.VERSION_1_8

targetCompatibility JavaVersion.VERSION_1_8

}

testOptions {

reportDir = "$project.buildDir/reports"

resultsDir = "$project.buildDir/test-results/junit"

}

dependenciesInfo {

includeInApk true

includeInBundle true

}

lint {

abortOnError false

checkDependencies true

checkGeneratedSources true

htmlOutput = file("$project.buildDir/reports/lint/LINT-results.html")

xmlOutput = file("$project.buildDir/test-results/lint/LINT-results.xml")

}

namespace 'com.linardsl.libhacontimig'

}

ext {

// System variables

supportLibraryVersion = '28.0.0'

clouddashProductVersion = ''

clouddashLibraryVersion = ''

}

dependencies {

implementation fileTree(dir: 'libs', include: ['*.jar'])

implementation "com.android.support:appcompat-v7:${supportLibraryVersion}"

implementation "com.android.support:design:${supportLibraryVersion}"

implementation 'com.android.support:multidex:1.0.3'

implementation "androidx.core:core:1.7.0" // core:1.7.0+ => 'compileSdkVersion' => SDK v31+

implementation 'androidx.appcompat:appcompat:1.3.1' // appcompat:appcompat:1.3.1+ => 'compileSdkVersion' => SDK v31+

// core:1.4.0+ => 'compileSdkVersion' => SDK v31+

implementation 'com.google.android.material:material:1.6.1'

// material:1.5.0+ => 'compileSdkVersion' => SDK v31+

implementation 'androidx.constraintlayout:constraintlayout:2.1.4'

implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

implementation 'androidx.preference:preference:1.2.0' // preference:1.2.0+ => 'compileSdkVersion' => SDK v31+

implementation 'com.google.android.play:core:1.10.3'

implementation 'com.google.android.gms:play-services-auth:20.3.0' //19.2.0

implementation 'com.google.android.gms:play-services-fitness:21.1.0' //20.0.0

implementation 'com.google.android.gms:play-services-ads:21.2.0' //21.0.0 20.3.0'

implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1' //17.1.0 17.0.1'

implementation 'com.google.android.gms:play-services-basement:18.1.0' //18.0.2 17.6.0

implementation 'com.google.ads.mediation:facebook:6.11.0.1'

// Declare the dependencies for the Crashlytics and Analytics libraries

// When using the BoM, you don't specify versions in Firebase library dependencies

implementation platform('com.google.firebase:firebase-bom:30.5.0') //:30.1.0 :29.2.1 firebase-bom:29.0.2+ => 'compileSdkVersion' => SDK v31+

implementation 'com.google.firebase:firebase-analytics'//:18.0.2'

implementation 'com.google.firebase:firebase-crashlytics'

implementation 'com.google.firebase:firebase-crashlytics-ndk'

implementation 'com.google.firebase:firebase-auth'//:21.0.1'//:17.4.0'

implementation 'com.google.firebase:firebase-messaging'//:23.0.0'

implementation 'com.google.firebase:firebase-perf'

implementation 'androidx.viewpager2:viewpager2:1.0.0'

testImplementation 'junit:junit:4.13.2'

testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.1' // 5.8.2

testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.1' // 5.8.2

testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.1' // 5.8.2

// Optional -- Robolectric environment

testImplementation 'androidx.test:core:1.4.0'

// Optional -- Mockito framework

testImplementation 'org.mockito:mockito-core:4.8.0'

androidTestImplementation 'androidx.test:rules:1.4.0'

androidTestImplementation 'androidx.test:runner:1.4.0'

androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

androidTestImplementation 'org.testng:testng:7.6.1'

// HTTP classes

// -- optional to use httpurlconnection-executor, any other HttpRequestExecutor implementation will do

implementation 'com.jakewharton.threetenabp:threetenabp:1.4.1'

// OAuth2-essentials

implementation 'org.dmfs:oauth2-essentials:0.18'

implementation 'org.dmfs:httpurlconnection-executor:1.16.2'

implementation 'androidx.browser:browser:1.4.0'

// browser:1.4.0+ => 'compileSdkVersion' => SDK v31+

// ndk for curl

implementation 'com.android.ndk.thirdparty:openssl:1.1.1l-beta-1'

implementation 'com.android.ndk.thirdparty:curl:7.79.1-beta-1'

// huawei

//implementation 'com.huawei.hms:hihealth-base:4.0.4.300'

implementation 'com.huawei.hihealth:hihealthkit:5.1.0.300' // (https://github.com/HMS-Core/hms-health-extention-demo/blob/master/HiHealthKitDemo/app/build.gradle)

implementation 'com.google.code.gson:gson:2.9.1'

implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.10'

implementation 'com.huawei.hms:base:6.7.0.300'

implementation 'com.huawei.hms:hwid:6.7.0.300'

implementation 'com.huawei.hms:game:6.7.0.300' //6.5.0.300 //5.0.4.303

implementation 'com.huawei.hms:health:6.7.0.300' //6.4.0.301 //6.3.0.301 //6.0.0.300

//implementation files('libs/hihealthkit-2.0.1.300.jar')

// version-compare

implementation("io.github.g00fy2:versioncompare:1.5.0")

// whats new

implementation 'io.github.tonnyl:whatsnew:0.1.7'

// badger

implementation 'me.leolin:ShortcutBadger:1.1.22'

// ironsource offerwall

implementation 'com.ironsource.sdk:mediationsdk:7.2.4.1'

// aws lex

implementation 'com.amazonaws:aws-android-sdk-lex:2.53.0'

// google health connect

implementation 'androidx.health.connect:connect-client:1.0.0-alpha05'

}

ProGuard .pro文件:

# Add project specific ProGuard rules here.

# You can control the set of applied configuration files using the

# proguardFiles setting in build.gradle.

#

# For more details, see

# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following

# and specify the fully qualified class name to the JavaScript interface

# class:

#-keepclassmembers class fqcn.of.javascript.interface.for.webview {

# public *;

#}

-keep public class com.linardsl.libhacontimig.MainActivity{

*;

}

# Uncomment this to preserve the line number information for

# debugging stack traces.

-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to

# hide the original source file name.

#-renamesourcefileattribute SourceFile

-printmapping mapping.txt

Android makefile:

# Build static module. See https://developer.android.com/ndk/guides/cmake

# Android Studio 4.0+ tutorial: https://stackoverflow.com/questions/44297396/compile-native-library-that-relies-on-other-native-libraries-to-run-using-androi

# https://android-developers.googleblog.com/2020/02/native-dependencies-in-android-studio-40.html

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_LDLIBS := -llog -landroid -lz

LOCAL_MODULE := integration

LOCAL_SRC_FILES := integration.c

LOCAL_CPP_FEATURES := rtti exceptions

LOCAL_MODULE_TAGS := optional

LOCAL_SHARED_LIBRARIES := curl

include $(BUILD_SHARED_LIBRARY)

$(call import-module, prefab/curl)

Application makefile:

# Build all API/ABI compatible binaries

APP_ABI := all

APP_SHORT_COMMANDS := true

# Include STL port lib

APP_STL := c++_shared

APP_CPPFLAGS := -std=c++17

#APP_CFLAGS := -Wall -Werror

# Build error workarounds

APP_ALLOW_MISSING_DEPS := true

如何修复此崩溃并使Java方法可调用和正常工作?我做错了什么?

0