2021年2月19日 星期五

hello_jni

環境: android_studio 4.1.2

Tree結構:
project_name(testJni)/app/src/main
$ tree
.
├── AndroidManifest.xml
├── java
│   └── com
│       └── example
│           └── testjni
│               ├── FirstFragment.java
│               ├── MainActivity.java
│               ├── SecondFragment.java
│               └── TestJni.java
├── jni (必要,自行產生)
│   ├── Android.mk
│   ├── Application.mk
│   ├── hello_jni.c
│   └── hello_jni.h
├── jniLibs (必要, 從 libs拷貝資料夾過來)
│   ├── x86
│   │   └── libhello_jni.so
│   └── x86_64
│       └── libhello_jni.so
├── libs (ndk-build產生)
│   ├── arm64-v8a
│   │   └── libhello_jni.so
│   ├── x86
│   │   ├── gdbserver
│   │   ├── gdb.setup
│   │   └── libhello_jni.so
│   └── x86_64
│       ├── gdbserver
│       ├── gdb.setup
│       └── libhello_jni.so
...
...
...
...


project_name(testJni)/
$ tree
├── gradle.properties
├── local.properties


local.properties
sdk.dir=/opt/android_studio/sdk
ndk.dir=/opt/android_studio/sdk/ndk/20.1.5948944/ (官方建議寫在 build.gradle)


build.gradle
android {
    compileSdkVersion 28
    buildToolsVersion '28.0.3'
    ...
    ...
    ndkVersion "20.1.5948944"
}


app/src/main/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testjni"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="16"
        android:targetSdkVersion="26" />


app/src/main/jni/hello_jni.c

#include <jni.h>
#include <stdio.h>
#include <android/log.h>
#include "hello_jni.h"

#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "TAG", __VA_ARGS__);
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "TAG", __VA_ARGS__);
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, "TAG", __VA_ARGS__);
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "TAG", __VA_ARGS__);
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "TAG", __VA_ARGS__);

//                        Java_pacakgeName_className_functionName
JNIEXPORT jstring JNICALL Java_com_example_testjni_TestJni_getString(JNIEnv * env, jobject obj, jstring s)
{
    char * st = (char *) (*env)->GetStringUTFChars(env, s, 0);
    LOGI("\n c-string:  %s", st);

    char * str = "hello_world";
    jstring rtn;
    rtn = (*env)->NewStringUTF(env, str);
    return rtn;
}


app/src/main/jni/hello_jni.h
#ifndef TESTJNI_HELLO_JNI_H
#define TESTJNI_HELLO_JNI_H
JNIEXPORT jstring JNICALL Java_com_example_testjni_TestJni_getString(JNIEnv * env, jobject obj, jstring s);
#endif //TESTJNI_HELLO_JNI_H


app/src/main/jni/Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := hello_jni

LOCAL_SRC_FILES := hello_jni.c

LOCAL_LDLIBS :=  -L$(SYSROOT)/usr/lib -llog

include $(BUILD_SHARED_LIBRARY)



app/src/main/jni/Application.mk.mk
APP_ABI := x86 (x86電腦的emulator用。本來用x86_64,但編譯時說找不到@@)
APP_PLATFORM := android-16
APP_STL := c++_shared
app_abi

Compiler:
$ cd path/testJni/app/src/main/jni
$ ndk-build

在/usr/local/bin產生個ndk-build的script
#!/bin/sh
#DIR="$(cd "$(dirname "$0")" && pwd)"
DIR="/opt/android_studio/sdk/ndk/20.1.5948944/"
$DIR/build/ndk-build "$@"


成功後,會產生libs和obj資料夾
將 libs/abi 資料夾拷貝到 jniLibs


app/src/main/TestJni.java
package com.example.testjni;

public class TestJni {
    public native String getString(String str);

    static {
        System.loadLibrary("hello_jni");
    }
}

app/src/main/MainActivity.java
package com.example.testjni;

import android.os.Bundle;

import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

import android.util.Log;
import android.view.View;

import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends AppCompatActivity {

    TestJni tj = new TestJni();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        Log.i("test_hello", "Start jni");
        Log.i("test_nello", "jni="+tj.getString("hello_jni"));
        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();

            }
        });
    }
...
...
...


這樣應該可以在emulator上執行了,開啟logcat應該看得到jni的輸出


bsp code (system/core/rootdir/etc/public.libraries.android.txt)
...
...
libstdc++.so 
libsync.so 
libvulkan.so 
libwebviewchromium_plat_support.so 
libz.so
libhello_jni.so 添加


ref:
內置應用so庫無法打開問題解決
AndroidStudio NDK開發【dlopen failed: library "libc++_shared.so" not found】報錯解決

沒有留言:

張貼留言