How to add JNI (C/C++ native code) to existing And

2020-05-15 15:06发布

Like the title says - how to add native code to existing Android Studio project, without breaking the current project, including gradle and proguard settings?

2条回答
▲ chillily
2楼-- · 2020-05-15 15:38

Since Android Studio 3.1 its possible easy way:

1. Create cpp folder inside app\src\main.

2. Create <YOUR_FILE_NAME>.cpp file in app\src\main\cpp path (e.g. native-lib.cpp)

3. Add CMakeLists.txt file to app folder.

In that file name of the library, .cpp file path and some other settings should be defined, e.g. (from new, empty Android Studio Project with C++ support):

# 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.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/cpp/native-lib.cpp )
                          ^^^^^^^^^^^^^^
                          YOUR_CPP_FILE_NAME

# 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.
                       native-lib

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

4. Add to build.gradle (Module app) externalNativeBuild tag with reference to CMakeLists.txt into android section:

android {
    compileSdkVersion 26
    defaultConfig {
        ...
    }
    buildTypes {
        ...
    }
    externalNativeBuild {               <--- these lines should be added
        cmake {                         <--- these lines should be added
            path "CMakeLists.txt"       <--- these lines should be added
        }                               <--- these lines should be added
    }                                   <--- these lines should be added
}

5. Add to build.gradle (Module app) externalNativeBuild tag with cmake tag into defaultConfig section:

...
defaultConfig {
    applicationId "<YOUR_APP_ID>"
    minSdkVersion 26
    targetSdkVersion 26
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"


    externalNativeBuild {   <--- these lines should be added
        cmake {             <--- these lines should be added
            cppFlags ""     <--- these lines should be added
        }                   <--- these lines should be added
    }                       <--- these lines should be added
}
...

(example of "basic" build.gradle file also available in new, empty Android Studio project with C++ support)

6. Resync Project with Gradle files

By clicking Sync Project Sync Project button on Toolbar in the toolbar. NB! In Android Studio 3.3, the icon is  Android Studio 3.3 Sync Project button on Toolbar.

Also, take a look at Official Tutorial.

PS. If files not shown in cpp folder:

try File/Invalidate Caches & Restart as Thinh Vu mentioned in his comment.

查看更多
做个烂人
3楼-- · 2020-05-15 15:44

Follow this steps from your existing project:

1. Modify build.gradle (Module app) to look like this (a lot changes!):

    apply plugin: 'com.android.model.application'

    model {
        android.signingConfigs {
            create ("myConfig") {
                keyAlias '--your-key-alias--'
                keyPassword '--key-password--'
                storeFile file('--/path/to/keystore.jks--')
                storePassword '--store-password--'
            }
        }
        android {
            compileSdkVersion 25
            buildToolsVersion '25.0.2'

            defaultConfig {
                applicationId "--your.app.name--"
                minSdkVersion.apiLevel 19
                targetSdkVersion.apiLevel 25
                versionCode 1
                versionName "1.0"
            }
            buildTypes {
                release {
                    minifyEnabled true
                    proguardFiles.add(file('proguard-android-optimize.txt'))
                    proguardFiles.add(file('proguard-rules.pro'))
                    signingConfig = $("android.signingConfigs.myConfig")
                }
            }
            ndk {
                moduleName "--c-file--"
                ldLibs.addAll(["android", "log"])
            }

        }
        android.dexOptions {
            javaMaxHeapSize "2048m"
        }
    }

    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        testCompile 'junit:junit:4.12'
        compile 'com.android.support:appcompat-v7:25.3.1'
    }

You can copy/paste the above code and modify at least the values with "--value--" to match yours.

2. Modify build.gradle (Project)

where it says something like this:

dependencies {
    classpath 'com.android.tools.build:gradle:2.3.3'
}

to this:

dependencies {
    classpath 'com.android.tools.build:gradle-experimental:0.9.3'
}

The number in my example 0.9.3 is the latest version of gradle-experimental to be found here. Eventually change your gradle version in gradle-wrapper.properties to the version recommended by Android Studio if you did not already.

3. Move your proguard settings file

proguard-android-optimize.txt to app/proguard-android-optimize.txt

4. Add the call from java

like this

static {
    System.loadLibrary("--c-file--");
}
private native byte my_jni(Context context, byte[] mByte, int i);

changing to your needs. The example above loads the c-file (write it without the extension) - the same one declared in the gradle file, and calls the function my_jni, passing the application's Context, some byte array and some int, expecting that the functions returns a byte.

5. Create the function in JNI:

Now the name of your function is highlighted in red - allow Android Studio to create it Create function ... with clicking on the red lamp on the row. This creates the function in your c file and changes focus to it.

Done

Further reading here.

Tips:

  • Take care to free everything you malloc, ReleaseByteArrayElements for every GetByteArrayElements and so on

  • Take care how to properly return some dangerous values from C to Java, like arrays and Strings

查看更多
登录 后发表回答