Android Studio使用总结

Android项目目录结构

Example
├── build
├── build.gradle
├── consumer-rules.pro
├── gradle
├── gradle.properties
├── gradlew
├── gradlew.bat
├── libs
├── local.properties
├── proguard-rules.pro
└── src
    ├── androidTest
    │   └── java
    │       └── com
    ├── main
    │   ├── AndroidManifest.xml
    │   ├── assets
    │   │   ├── config.json
    │   │   ├── entity
    │   │   └── words
    │   ├── cpp
    │   │   ├── CMakeLists.txt
    │   │   └── vad_jni.cpp
    │   ├── java
    │   │   └── com
    │   ├── jniLibs
    │   │   ├── arm64-v8a
    │   │   └── armeabi-v7a
    │   └── res
    └── test
        └── java
            └── com

我们比较关心的目录是libssrc

JNI 示例

动态库放置位置

  1. 在Android Studio中,项目中依赖的动态库会默认匹配到 src/main/jniLibs 目录
  2. 原则上,所有的动/静态库都放到 src/main/jniLibs 目录下

build.gradle 配置

android {
	...
	defaultConfig {
	    ...
        externalNativeBuild {
            cmake {
                cppFlags "-std=c++14 -frtti -fexceptions"
                abiFilters "armeabi-v7a", "arm64-v8a"
            }
        }
    }

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

C/CPP源码位置

在 Android Studio中,使用CMake作为编译工具,JNI C/CPP 源码会放到 src/main/cpp 目录或者 src/main/jni,具体的目录名称要和build.gradle中配置 CMakeLists.txt 的位置相同

Example
└─ src
     ├─ main
     │   ├─ cpp
     │   │    ├── CMakeLists.txt
     │   │    └── demo_jni.cpp
     └───└─ java
               └── com
                      └── example
                              └── jni
                                      └── Demo.java

CMakeLists.txt 内容(名字不能错)

cmake_minimum_required(VERSION 3.4.1)

add_library(demo_jni SHARED)
include_directories("${PROJECT_SOURCE_DIR}/include")
target_sources(demo_jni PUBLIC vad_jni.cpp)
target_link_libraries(demo_jni -llog)

添加三方动态库的依赖

在CMakeLists文件中添加如下语句:

target_link_libraries(demo_jni ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}/libxxx.so)

CMAKE_ANDROID_ARCH_ABI: 当前编译的 ABI。

静态注册示例

demo_jni.cpp 源码

#include <jni.h>
#include <android/log.h>

#define LOG_TAG "demo_jni"
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

extern "C" {

void Java_com_example_jni_Demo_demo_1init(JNIEnv *env, jobject clazz)
{
    LOGD("jni demo");
    return;
}

jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
    return JNI_VERSION_1_6;
}

void JNI_OnUnload(JavaVM *vm, void *reserved)
{
    return;
}
    
}

Demo.java 源码

  • 加载动态库
  • 声明 native 方法
package com.example.jni;

public class Demo {
    static {
        System.loadLibrary("demo_jni");
    }

    public native void demo_init();
}

动态注册和多个类JNI实例

MainActivity

package com.example.jnidemo;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    public JNIClassA jniClassA;
    public JNIClassB jniClassB;

    static {
        System.loadLibrary("jni_demo");
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        jniClassA = new JNIClassA();
        jniClassB = new JNIClassB();

        jniClassA.printA();
        jniClassB.printB();
    }
}

JNIClassA

package com.example.jnidemo;

public class JNIClassA {
    public native int printA();
}

JNIClassB

package com.example.jnidemo;

public class JNIClassB {
    public native int printB();
}

com_example_jnidemo_JNIClassA

Header

#ifndef JNIDEMO_COM_EXAMPLE_JNIDEMO_JNICLASSA_H
#define JNIDEMO_COM_EXAMPLE_JNIDEMO_JNICLASSA_H

#include <jni_demo.h>

#ifdef __cplusplus
extern "C" {
#endif

jint registerJNIClassA(JNIEnv *env);

#ifdef __cplusplus
}
#endif

#endif //JNIDEMO_COM_EXAMPLE_JNIDEMO_JNICLASSA_H

CPP

#include "jni_demo.h"

#ifdef __cplusplus
extern "C" {
#endif

static const char *jclass_ClassB_name = "com/example/jnidemo/JNIClassB";
static jclass jclass_ClassB = NULL;

static jint print_B(JNIEnv *env, jobject clazz)
{
    LOGD("%s, %d print_B", __FILE__, __LINE__);
    return 0;
}

static JNINativeMethod classB_methods[] = {
        {"printB", "()I", (void *)print_B}
};

jint registerJNIClassB(JNIEnv *env)
{
    jclass_ClassB = env->FindClass(jclass_ClassB_name);
    if (jclass_ClassB == NULL) {
        LOGE("can't find %s", jclass_ClassB_name);
        return -1;
    }

    int err = env->RegisterNatives(jclass_ClassB, classB_methods, sizeof(classB_methods)/ sizeof(classB_methods[0]));
    if (err != 0) {
        LOGE("call RegisterNatives failed, %s", __FILE__);
        return -1;
    }
    return 0;
}

#ifdef __cplusplus
}
#endif

com_example_jnidemo_JNIClassB

Header

#ifndef JNIDEMO_COM_EXAMPLE_JNIDEMO_JNICLASSB_H
#define JNIDEMO_COM_EXAMPLE_JNIDEMO_JNICLASSB_H

#include <jni_demo.h>

#ifdef __cplusplus
extern "C" {
#endif

jint registerJNIClassB(JNIEnv *env);

#ifdef __cplusplus
}
#endif

#endif //JNIDEMO_COM_EXAMPLE_JNIDEMO_JNICLASSB_H

CPP

#include "jni_demo.h"

#ifdef __cplusplus
extern "C" {
#endif

static const char *jclass_ClassB_name = "com/example/jnidemo/JNIClassB";
static jclass jclass_ClassB = NULL;

static jint print_B(JNIEnv *env, jobject clazz)
{
    LOGD("%s, %d print_B", __FILE__, __LINE__);
    return 0;
}

static JNINativeMethod classB_methods[] = {
        {"printB", "()I", (void *)print_B}
};

jint registerJNIClassB(JNIEnv *env)
{
    jclass_ClassB = env->FindClass(jclass_ClassB_name);
    if (jclass_ClassB == NULL) {
        LOGE("can't find %s", jclass_ClassB_name);
        return -1;
    }

    int err = env->RegisterNatives(jclass_ClassB, classB_methods, sizeof(classB_methods)/ sizeof(classB_methods[0]));
    if (err != 0) {
        LOGE("call RegisterNatives failed, %s", __FILE__);
        return -1;
    }
    return 0;
}

#ifdef __cplusplus
}
#endif

jni_demo

#ifndef JNIDEMO_JNI_DEMO_H
#define JNIDEMO_JNI_DEMO_H

#include <jni.h>
#include <android/log.h>

#ifdef __cplusplus
extern "C" {
#endif

#define LOG_TAG "jni_demo"
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

#ifdef __cplusplus
}
#endif

#endif //JNIDEMO_JNI_DEMO_H

CPP


#include "jni_demo.h"
#include <com_example_jnidemo_JNIClassA.h>
#include <com_example_jnidemo_JNIClassB.h>

#ifdef __cplusplus
extern "C" {
#endif

static jint registerNativeMethods(JNIEnv* env) {
    jint err = registerJNIClassA(env);
    if (err != 0) {
        LOGE("failed to registerJNIClassA, err: %d", err);
        return err;
    }

    err = registerJNIClassB(env);
    if (err != 0) {
        LOGE("failed to registerJNIClassB, err: %d", err);
        return err;
    }

    return 0;
}

jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env = NULL;

    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        return -1;
    }

    if (env == NULL) {
        LOGE("JNI_OnLoad error, should never happen.");
        return -1;
    }

    jint err = registerNativeMethods(env);
    if (err != 0) {
        LOGE("failed to register native methods, err: %d", err);
        return err;
    }
    return JNI_VERSION_1_6;
}

void JNI_OnUnload(JavaVM *vm, void *reserved) {
    return;
}

#ifdef __cplusplus
}
#endif

build gradle配置

jar/aar 包导入

将 jar 或者 aar 包放入 $PROJECT/app/libs 目录,并确认 $PROJECT/app/build.gradle 文件包含下面的内容:

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
}

Instrumented Test

issues

permission denied

问题

plugin: ‘com.android.library’ not found

解决:在 build.gradle 中添加下面内容

allprojects {
    repositories {
        google()
        jcenter()

    }
}

buildscript {
    ext.kotlin_version = '1.3.72'

    repositories {
        google()
        jcenter()

    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.0.0'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

Bad encoded_value method type size 7

add compileOptions { targetCompatibility JavaVersion.VERSION_1_8 } in build:gradle(:app) under the android section.

android {
    compileOptions { targetCompatibility JavaVersion.VERSION_1_8 }
}

gradle: connection reset

  1. ping dl.google.com,确定是否能连接到google网络

Build Output 汉字乱码解决方案

  1. AS内自带的全局搜索功能,搜索 Edit Custom VM Options

  2. 添加下面内容:

    -Dfile.encoding=UTF-8
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值