Android 积累一些JNI与NDK的知识

最近项目中要用到一些同屏操作,起初的方案是不断记录坐标,上传坐标,来达到画笔的同屏。但实际演示的时候效果并不好,于是我在想可不可以像视频录制一样直接调用底层,体验永远是程序质量的第一标准,不能因为自己的能力限制所妥协。但问题接踵而至,因为jvm的跨平台的特性,注定导致java跟底层几乎没什么联系。但是java能调用c方法,通过JNI的方式。在android程序中要想调用c方法,就要用到NDK,平常JNI和NDK说的很溜,其实我也不知道JNI与NDK的区别:


1.JNI与NDK的定义:


JNI:

Java Native Interface(Java 本地接口)
方便Java调用C,C++等本地代码所封装的一层接口

NDK:

Android 提供的一个工具集合(native develop kits),这套工具集允许你为android使用c或c++代码,并提供众多的平台库让你管理原生的activity和物理设备组件
通过NDK可以在android中更加方便的通过JNI来访问本地代码
交叉编译的工具链:在一个平台下,编译出来在另一个平台下可以执行的代码
.c 与 .java
1.编译:把源代码编译成一个低级语言,
2.链接:根据具体平台的特性,链接成一个二进制可执行的程序




工作环境()

应该是一个android程序员想要调用c方法,他要写成native方法,然后把nativie方法弄成头文件,
c程序员根据头文件里的方法,对其中的方法做实现,然后给android程序员再弄成so文件,弄成文件就简单了,开发过百度地图的都知道,建立jniLibs,将so文件放入,调用方法,实现功能。

运行环境:

as2.3.1

window64

ndk:android-ndk-r13b


NDK比较古老的使用方式:使用ndk-build命令


之前eclipse上使用ndk,或者ndk更早版本的时候,在官方的ndk目录里有ndk-build的文件,可惜只能在linux环境下运行,估计还要下cygwin模拟linux环境还要配置环境变量,而现在比较高的版本的ndk文件目录下有ndk-build.cmd文件,方便里我们可以直接在Android studo的Terminal控制台下直接编译成so库。


前言:

1.运行环境很重要,本人实验了一下午,发现低版本的ndk害死人,老是出Error:Execution failed for task ':app:compileDebugNdk'.这个错误,纠结代码半天,其实压根跟代码没啥关系

2.32位的系统androidstudio用不了cmake

3.android_studio看不了.mk文件

操作流程:

1.配置NDK与环境变量


配置ndk的环境变量跟配置jdk的环境变量差不多,自行百度

2.建立项目声明native方法
package com.wyt.hcy.libjpegandroid;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

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

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv= (TextView) findViewById(R.id.tv);
        tv.setText(helloFromC());
    }




    public native String helloFromC();
}





3.形成头文件

在studio terminal中输入指令,切换到项目的目录,并输入javah 包名. MainActivity



刷新就会看到产生的头文件





点开这个头文件:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_wyt_hcy_libjpegandroid_MainActivity */

#ifndef _Included_com_wyt_hcy_libjpegandroid_MainActivity
#define _Included_com_wyt_hcy_libjpegandroid_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_wyt_hcy_libjpegandroid_MainActivity
 * Method:    helloFromC
 * Signature: ()Ljava/lang/String;
 */

/**
 * 函数名的格式Java_包名_类名_方法
 * JNIEnv:表示一个指向JNi环境的指针
 * jobject:表示java中的this
 * JNICALL,JNIEXPORT:表示JNi定义的宏
 */
JNIEXPORT jstring JNICALL Java_com_wyt_hcy_libjpegandroid_MainActivity_helloFromC
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

4.根据头文件实现方法

建立jni文件夹,选择main目录右键,new/folder/jnifolder

将头文件剪切到jni目录下

这里以c语言为例,在jni目录下建立Hello.c文件,要引入头文件
#include<stdio.h>
#include<jni.h>
#include "com_wyt_hcy_libjpegandroid_MainActivity.h"


JNIEXPORT jstring JNICALL Java_com_wyt_hcy_libjpegandroid_MainActivity_helloFromC(JNIEnv *env, jobject obj)
{

    return (*(*env)).NewStringUTF(env, "HelloWorldFromC");
}



5.编成so库

A。在jni目录下建立Android.mk文件(此文件名称固定:交叉编译器在编译c或者c++语言所依赖的配置文件符合linux下makefile的语法ziji),文件名字固定(不知道为什么),as是能建立.mk文件的,但打不开。



这里我用subnlite text打开它,在android.mk里输入

LOCAL_PATH := ${call my-dir}
include ${CLEAR_VARS}
LOCAL_MODULE :=Hello
LOCAL_SRC_FILES :=Hello.c
include ${BUILD_SHARED_LIBRARY}

LOCAL_PATH := ${call my-dir}  获取当前Android.mk文件的路径
include ${CLEAR_VARS}       变量的初始化但不会初始化LOCAL_PATH
LOCAL_MODULE :=Hello        libHello.so 表示模块名称,即:MainActivity静态代码块填写的
LOCAL_SRC_FILES :          表示参与编译的源文件



B。在项目的gradle.properties里配置:

android.useDeprecatedNdk=true


C。最后在module的build.grade里输入:(一定要在android里的
defaultConfig代码块里写:

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "com.wyt.hcy.libjpegandroid"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        ndk{
            moduleName "Hello"
            // abiFilters "armeabi", "armeabi-v7a", "x86"  //输出指定三种abi体系结构下的so库。目前可有可无。
        }

    }



在Terninal控制台里输入ndk-build成功就会返回




编译成功的话:在jni同级目录下会多了个libs目录,还能看到libHello.so



然后clean,运行就会看到textview调用了c代码


运行中出错:Error:Execution failed for task ':app:compileDebugNdk'. 

个人觉得不应该向其他人说的添加一个空的c文件就能解决的:

1.看看您
在项目的gradle.properties里配置:




2.看看项目的gradle里有没有设置ndk,或者当前项目的ndk版本是否跟你环境变量的版本一致



ndk-build clean 该命令可以删除编译的缓存



下面我们进行更深层次的探索


1.什么是cmake

一款外部构建工具,可与 Gradle 搭配使用来构建原生库。如果您只计划使用 ndk-build,则不需要此组件。

2.什么是LLDB

一种调试程序,Android Studio 使用它来调试原生代码。  


//最近我一直想使用libjpeg-turbo这个开源库,但我一直没找到如何将这个开源库编译成android的版本的方法,一开始我看教程上说,只要把开源库里的c文件得名字都放进Android.mk文件里just like:

 

我展示too young,以为直接编译能成功结果问题太多

jinclude.h:23:10: fatal error: 'jconfig.h' file not found
jpeglib.h:69:9: error: unknown type name 'JSAMPLE'

结果我就傻眼了,百度这些问题,压根没找到有用的,由于自己c语言早已忘得一干二净

于是我今天又找了个项目:项目下载链接

只要将文件复制到项目的jni目录下:打开as 控制台输入:

ndk-build APP_ABI=armeabi-v7a,armeabi
虽然有些警告,但直接编译成功了















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值