Saya baru dalam pengembangan NDK, saya membuat proyek dengan dukungan C++. Namun saya baru saja menambahkan 1 kelas cpp dan menghasilkan file .SO. Dan mencoba mengakses file itu di proyek lain. Saya merujuk banyak tautan stackoverflow, Blog, dan situs pengembang Google. Namun tidak mampu menyelesaikannya. Ini kode saya.

Lokal.properti

ndk.dir=/home/android/Android/Sdk/ndk/20.1.5948944
sdk.dir=/home/android/Android/Sdk

Src/main/cpp/CMakeLists.txt

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
        hello_world_lib

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        hello_world_lib.cpp
        HelloWorld.cpp
        )

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        hello_world_lib

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

Src/main/cpp/hello_world_lib.cpp

#include <jni.h>
#include <string>
#include <bitset>
#include "HelloWorld.h"

extern "C" JNIEXPORT jstring JNICALL
Java_com_dc_testapplication_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

extern "C" JNIEXPORT jint JNICALL
Java_com_dc_testapplication_MainActivity_getSumOfValues(JNIEnv *env,
                                                        jobject,jint a ,jint b,jstring sign){

    // working Solution
    const char *nativeString = env->GetStringUTFChars(sign, 0);


    HelloWorld helloWorld;
    helloWorld.setValues((int)a,(int)b);
    helloWorld.setOperationType(*nativeString);

    jint mData = (jint)helloWorld.getSumOf2Values();
    return mData;
}

Saya mendapat begitu file dari sini setelah membangun/menjalankan aplikasi. app/build/intermediates/cmake/debug/obj/{abis}/{nameoflib}.so

Sekarang saya perlu mengakses file .so ini di proyek lain. Dan nama paketnya adalah com.dc.usendklib. Sekarang di sini adalah Kode proyek baru saya.

App/libs/{nama folder abi}/.so file. src/main/jniLibs/{nama folder abi}/.so

Src/main/jniLibs/Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := hello_world_lib-prebuilt
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libhello_world_lib.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)

Src/main/jniLibs/Application.mk

APP_ABI := armeabi-v7a arm64-v8a x86

Tingkat aplikasi

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"

    sourceSets.main {
        jniLibs.srcDir 'src/main/jniLibs' //set .so files location to libs
        jni.srcDirs = [] //disable automatic ndk-build call
    }

    defaultConfig {
        applicationId "com.dc.usendklib"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

        ndk {
            moduleName "hello_world_lib"
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

//    sourceSets {
//        main {
//            // let gradle pack the shared library into apk
//            jniLibs.srcDirs = ['src/main/jniLibs','src/main/CPP']
//        }
//    }

//    sourceSets.main {
//        jniLibs.srcDir 'src/main/jniLibs'
//    }

//    externalNativeBuild {
//        cmake {
//            path "src/main/cpp/CMakeLists.txt"
//            version "3.10.2"
//        }
//    }

}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.core:core-ktx:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

Dan ketika saya menjalankan ini, saya mendapatkan kesalahan ini.

2020-01-03 11:44:54.946 17235-17235/com.dc.usendklib E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.dc.usendklib, PID: 17235
    java.lang.UnsatisfiedLinkError: No implementation found for java.lang.String com.dc.usendklib.MainActivity.stringFromJNI() (tried Java_com_dc_usendklib_MainActivity_stringFromJNI and Java_com_dc_usendklib_MainActivity_stringFromJNI__)
        at com.dc.usendklib.MainActivity.stringFromJNI(Native Method)
        at com.dc.usendklib.MainActivity.onCreate(MainActivity.kt:14)
        at android.app.Activity.performCreate(Activity.java:7136)
        at android.app.Activity.performCreate(Activity.java:7127)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

Aktivitas Utama.kt

package com.dc.usendklib

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Example of a call to a native method
        sample_text.text = stringFromJNI()
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    external fun stringFromJNI(): String

    companion object {

        // Used to load the 'native-lib' library on application startup.
        init {
            System.loadLibrary("hello_world_lib")
        }
    }
}

Sekarang pertanyaan saya adalah,

  1. Cara saya menghasilkan dan memilih file .so, apakah itu cara yang benar?

  2. Metode kelas JNI menggunakan Java_{package}_method, Jadi setelah menghasilkan .so, apakah mungkin menggunakan file itu di proyek lain?

  3. Jika ya, beri tahu saya bagaimana. Bantuan apa pun akan dihargai. Terima kasih sebelumnya.

1
GreenFlash 3 Januari 2020, 09:22

2 jawaban

Jawaban Terbaik

Ya, Anda dapat mengakses file so Anda ke proyek lain. tetapi direktori proyek Anda harus sama dengan proyek lama Anda. dalam direktori proyek kasus Anda harus seperti ini:

com/dc/testapplication/MainActivity.class Dan MainActivity.class Anda harus memiliki metode getSumOfValues.

1
Mukesh Wondersoft 3 Januari 2020, 10:49

Java_com_dc_testapplication_MainActivity_stringFromJNI

Seharusnya kelas "pembungkus" Anda di MainActivity dari paket com.dc.testapplication

Tapi, sejauh yang saya lihat di posting Anda, MainActivity Anda terletak di com.dc.usendklib. Itu sebabnya Anda memiliki UnsatisfiedLinkError.

Anda dapat melihat kasus saya untuk memahami cara kerjanya

1
Bruno 3 Januari 2020, 08:12