Android Studio 1.4.x JNI开发配置


     由于需要在PC和安卓之间进行h264编码打包rtp传输,需要在安卓端进行rtp包接收和解码,因此需要进行NDK开发;
     下载安装Android Studio 1.4后看介绍发现较之之前版本(1.3以前),对NDK的支持变好,配置NDK不用以前那样写mk文件;
     于是参考http://www.cnblogs.com/zhuyp1015/p/4976116.html
     《Android Studio1.4.x JNI开发基础-基本环境配置》,基本上完成配置,但自己这由于一些出入,总遇到些莫名其妙的问题,所以还是自己记录一遍已做备忘,同时作为第一篇博客;
     步骤基本和http://www.cnblogs.com/zhuyp1015/p/4976116.html相同,但还是贴一遍;
     -------------------
     一、首先准备基本工具,Android Studio (>=1.3.x), NDK(ndk-r10-e)。打开Android Studio 建立一个空工程,关联上NDK,操作步骤方式如下图:

这里写图片描述
下一步
这里写图片描述
这里我选择安卓4.4以上;
二、设置ndk路径
file->project structure
这里写图片描述
gradle version 输入2.5
这里写图片描述
三、开始设置gradle
1、首先设置TopLevel gradle,也就是Project gradle,这里比较简单,在dependencies中设置:
classpath ‘com.android.tools.build:gradle-experimental:0.2.0’
注意这里要把之前的类似classpath ‘com.android.tools.build:gradle:1.3.0’ 注释掉。
这里写图片描述
2、接着设置 Module gradle,这一步是比较麻烦的。由于我们在创建工程的时候自动生成的这个gradle文件内容比较多,而且如果要使用NDK的话这个gradle变化比较大,这里直接贴出需要使用NDK的gradle,然后来进行说明。

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

model {
    android {
        compileSdkVersion = 23//根据自己需要以及安装的内容选择版本
        buildToolsVersion = "23.0.2"//没有的话可用sdk manager安装

        packagingOptions.with {
            exclude 'META-INF/LICENSE.txt'
            exclude 'META-INF/NOTICE.txt'
        }

        defaultConfig.with {
            applicationId = "com.zyp.ndktest"
            minSdkVersion.apiLevel  = 19  // Unable to load class com.android.build.gradle.managed.ProductFlavor_Impl
            targetSdkVersion.apiLevel = 21
            versionCode = 1
            versionName = "1.0"
        }

    }
    android.buildTypes {
        //debug {
        //}
        release {
            minifyEnabled = false
            proguardFiles += file('proguard-rules.pro')
        }
    }


    compileOptions.with {
        sourceCompatibility = JavaVersion.VERSION_1_7
        targetCompatibility = JavaVersion.VERSION_1_7
    }
    android.ndk {
        moduleName = "NdkSample"//设置的so文件名
        cppFlags += "-std=c++11"
        cppFlags += "-fexceptions"
        cppFlags += "-I${file("src/main/jni//include")}".toString()
        ldLibs += ["android", "log"]
        stl = "gnustl_shared"
    }

    //将会在app\build\intermediates\binaries\debug目录下生成相印文件,内有响应平台的NdkSample.so文件
    android.productFlavors {
        create("arm7") {
            ndk.abiFilters.add("armeabi-v7a")
            ndk.abiFilters.add("armeabi")
        }
        create("arm8") {
            ndk.abiFilters.add("arm64-v8a")
        }

    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile 'com.android.support:appcompat-v7:23.0.0'
    compile 'com.android.support:design:23.0.1'
}

这个gradle的配置有几点需要注意的:
i.首先是 apply plugin: ‘com.android.application’ 变成了 apply plugin: ‘com.android.model.application’。
ii.所有值的设置都要写成 xxx = yyyy的形式,比如: applicationId = “com.zyp.ndktest” (自动生成的gradle 则可能是: applicationId = “com.zyp.ndktest” ),否则会爆这种错误:Error:Cause: org.gradle.api.internal.ExtensibleDynamicObject, 当出现此类错误,检查是否都用了 “=”的方式。
iii.buildTypes 需要从android{} 中取出来,写成android.buildTypes{}的形式,否则会出现这种错误:Error:Unable to load class ‘org.gradle.nativeplatform.internal.DefaultBuildType_Decorated’.
iv.defaultConfig{} 需要写成defaultConfig.with{} 的形式,否则会报这种错误:Error:Cause: com.android.build.gradle.managed.AndroidConfig_Impl.
v.在defaultConfig.with{} 中 需要写成

    minSdkVersion.apiLevel = 19
    targetSdkVersion.apiLevel = 23
    也就是比自动生成的多 .apiLevel ,否则会报这种错误:Unable to load class com.android.build.gradle.managed.ProductFlavor_Impl.
vi.增加compileOptions.with{} 需要选择JavaVersion.VERSION_1_7,否则会报这种错误:Bad class file magic or version.
vii.最后一点,在gradleWrapper中使用的是2.5,则android.ndk {} 中类似cppFlags 的添加使用 += 的方式,否则需要使用 .add的方式
四、创建jni文件夹,然后编写Native代码
这里写图片描述
添加cpp/h文件:
NDKTEST.h:

#ifndef NDKTEST_NDKTEST_H
#define NDKTEST_NDKTEST_H

#include "jni.h"
#include <stdio.h>
#include <string.h>

extern "C" {
JNIEXPORT jstring JNICALL
        Java_nbicc_ffmpeg_1test_MainActivity_sayHello(JNIEnv *env, jclass type,
                                                      jstring filename);
}

#endif //NDKTEST_NDKTEST_H

NDKTEST.cpp:

#include "NDKTEST.h"

JNIEXPORT jstring JNICALL Java_nbicc_ffmpeg_1test_MainActivity_sayHello
        (JNIEnv *env, jclass cls, jstring j_str)
{
    const char *c_str = nullptr;
    char buff[128] = {0};
    jboolean isCopy;
    c_str = env->GetStringUTFChars(j_str, &isCopy);
    printf("isCopy:%d\n",isCopy);
    if(c_str == NULL)
    {
        return NULL;
    }
    printf("C_str: %s \n", c_str);
    sprintf(buff, "hello %s", c_str);
    env->ReleaseStringUTFChars(j_str, c_str);
    return env->NewStringUTF(buff);
}

五、编译生成libNDKTEST.so
这里写图片描述
此时在app\build\intermediates\binaries\debug\目录下已经生成了so文件
这里写图片描述
六、在java中使用jni编译得到的so文件
打开项目新建得到的或者你自己建立的Activity
开头加入:

import android.util.Log;

定义函数:

 public native static String sayHello(String str);

引入jni编译得到的so文件:

 static {
        System.loadLibrary("NDKTEST");
    }
 //注意这里不需要前缀lib以及扩展名.so,会自动到app\build\intermediates\binaries\debug\目录下寻找相应的libNDKTEST.SO

修改protected void onCreate:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        String ret = sayHello("zhuzhu");
        Log.i("JNI_INFO", ret);
    }

完整的代码为:

package nbicc.ndktest;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    public native static String sayHello(String str);
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        String ret = sayHello("string input");
        Log.i("JNI_INFO", ret);
    }

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

七、连上手机或用模拟器运行
这里写图片描述
结果发现程序安装到手机后,运行时提示已经停止运行;
查看android monitor上的提示:

No implementation found for java.lang.String nbicc.ndktest.MainActivity.sayHello(java.lang.String) (tried **Java_nbicc_ndktest_MainActivity_sayHello** and **Java_nbicc_ndktest_MainActivity_sayHello__Ljava_lang_String_2**)

意思是sayHello在NDKTEST.h和NDKTEST.cpp上的名字不对,改成上面加粗的名字中的任意一个即可

JNIEXPORT jstring JNICALL
        Java_nbicc_ndktest_MainActivity_sayHello(JNIEnv *env, jclass type,
                                                      jstring filename);
}

其实按照以前版本的ndk配置方法,.h文件是在java层定义
public native static String sayHello(String str);后build->Make project,通过javah生成的,接口函数名称Java_nbicc_ndktest_MainActivity_sayHello也是自动生成的,在这里反过来改名,更加方便一些;
重新编译,然后手机上运行,OK通过了
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值