I am trying to call Java method from C class file, built using NDK.
It constantly throws usual "no non-static method found" error and crashes whole Android App.
Code pieces below (some stuff might be not needed, but I left them as-is because focus/question is on refreshJNIIntegration() method, not the well-formatting of code in general).
Java class:
@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("<obfusciated>")) {
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<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
GoogleSignInAccount account = task.getResult(ApiException.class);
if (account!=null) {
if (BuildConfig.FLAVOR.endsWith("<obfusciated>")) {
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 class (which is initially called from Java and then calls method below) in integraton.c
file:
#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 class (where error and crash happens) in integraton.c
file:
#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 file:
/*
* 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 '<obfusciated>'
keyPassword '<obfusciated>'
keyAlias = '<obfusciated>'
} 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', "<obfusciated>"
}
alphaPro {
dimension "version"
applicationIdSuffix ".alphaPro"
versionNameSuffix "-alphaPro"
buildConfigField "boolean", "IS_BLEEDING", "true"
resValue 'string', 'app_name', "<obfusciated>"
}
beta {
dimension "version"
applicationIdSuffix ".beta"
versionNameSuffix "-beta"
buildConfigField "boolean", "IS_BLEEDING", "true"
resValue 'string', 'app_name', "<obfusciated>"
}
betaPro {
dimension "version"
applicationIdSuffix ".betaPro"
versionNameSuffix "-betaPro"
buildConfigField "boolean", "IS_BLEEDING", "true"
resValue 'string', 'app_name', "<obfusciated>"
}
demo {
dimension "version"
applicationIdSuffix ".demo"
versionNameSuffix "-demo"
buildConfigField "boolean", "IS_BLEEDING", "false"
resValue 'string', 'app_name', "<obfusciated>"
}
production {
dimension "version"
applicationIdSuffix ".final"
versionNameSuffix "-final"
buildConfigField "boolean", "IS_BLEEDING", "false"
resValue 'string', 'app_name', "<obfusciated>"
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 = '<obfusciated>'
clouddashLibraryVersion = '<obfusciated>'
}
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 file:
# 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
How to fix this crash and get Java method callable and working? What am I doing wrong?
UPDATE: Adding initial java-to-native method, build.gradle (module level) and android.mk file snipps as requested.
UPDATE: Bugs created in GitHub and google issue tracker: