02_JNI中Java代码调用C代码,Android中使用log库打印日志,javah命令的使用,Android.mk文件的编写,交叉编译

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 1  编写以下案例(下面的三个按钮都调用了底层的C语言):项目案例的代码结构如下:2 编写DataProvider的代码: package com.example.ndkpassdata;   public class DataProvider {         /**      * 计算x和y的加法  apktools      *


1  编写以下案例(下面的三个按钮都调用了底层的C语言)

项目案例的代码结构如下:

2 编写DataProvider的代码:

package com.example.ndkpassdata;

 

public class DataProvider {

   

    /**

     * 计算xy的加法  apktools

     *

     * @param x

     * @param y

     * @return

     */

    public native int add(int x,int y);

   

    /**

     * 给字符串后面拼接字符串   加密运算   web   url

     * @param s

     * @return

     */

    public native String sayHelloInC(String s);

   

    /**

     * C代码传递int数组   C代码给这个数组进行操作

     * 图形   声音的处理

     *

     * @param iNum

     * @return

     */

    public native int[] intMethod(int[] iNum);

}

3 MainActivity的代码如下:

package com.example.ndkpassdata;

 

import android.annotation.SuppressLint;

import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.widget.Toast;

 

public class MainActivity extends Activity {

         DataProvider provider;

         static{

                   System.loadLibrary("hello");

         }

        

         @Override

         protected void onCreate(Bundle savedInstanceState) {

                   super.onCreate(savedInstanceState);

                   setContentView(R.layout.activity_main);

                   provider=new DataProvider();

         }

        

         @SuppressLint("ShowToast")

         public void click1(View view){

                   int result=provider.add(3, 5);

                   Toast.makeText(getApplicationContext(), "provider.add(3, 5) = " + result, 0).show();

         }

        

         @SuppressLint("ShowToast")

         public void click2(View view){

                   String str=provider.sayHelloInC("yll");

                   Toast.makeText(getApplicationContext(), str, 0).show();

         }

        

         public void click3(View view){

                   int[] arr=new int[]{1,2,3,4,5};

                   provider.intMethod(arr);

                   for(int i:arr){

                            System.out.println(i);

                   }

         }

}

4 通过DataProvider生成C语言的头文件

进入/cygdrive/e/workspace/Android/NdkPassData/src目录下:

查看DataProvider的全路径:

在项目中生成头文件

头文件的内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/* Header for class com_example_ndkpassdata_DataProvider */

 

#ifndef _Included_com_example_ndkpassdata_DataProvider

#define _Included_com_example_ndkpassdata_DataProvider

#ifdef __cplusplus

extern "C" {

#endif

/*

 * Class:     com_example_ndkpassdata_DataProvider

 * Method:    add

 * Signature: (II)I

 */

JNIEXPORT jint JNICALL Java_com_example_ndkpassdata_DataProvider_add

  (JNIEnv *, jobject, jint, jint);

 

/*

 * Class:     com_example_ndkpassdata_DataProvider

 * Method:    sayHelloInC

 * Signature: (Ljava/lang/String;)Ljava/lang/String;

 */

JNIEXPORT jstring JNICALL Java_com_example_ndkpassdata_DataProvider_sayHelloInC

  (JNIEnv *, jobject, jstring);

 

/*

 * Class:     com_example_ndkpassdata_DataProvider

 * Method:    intMethod

 * Signature: ([I)[I

 */

JNIEXPORT jintArray JNICALL Java_com_example_ndkpassdata_DataProvider_intMethod

  (JNIEnv *, jobject, jintArray);

 

#ifdef __cplusplus

}

#endif

#endif

5 在项目下创建一个文件夹jni,将上面生成的头文件拷贝到这个文件夹下:

然后按照头文件,编写hello.c,hello.c的代码如下:

#include <stdio.h>

#include "com_example_ndkpassdata_DataProvider.h"

#include <android/log.h>

#include <string.h>

#define LOG_TAG "clog"

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

#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

 

/**

 * Java中的字符串转换成为C语言的字符

 */

char*   Jstring2CStr(JNIEnv*   env,   jstring   jstr)

{

     char*   rtn   =   NULL;

     jclass   clsstring   =   (*env)->FindClass(env,"java/lang/String");

     jstring   strencode   =   (*env)->NewStringUTF(env,"GB2312");

     jmethodID   mid   =   (*env)->GetMethodID(env,clsstring,   "getBytes",   "(Ljava/lang/String;)[B");

     jbyteArray   barr=   (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312");

     jsize   alen   =   (*env)->GetArrayLength(env,barr);

     jbyte*   ba   =   (*env)->GetByteArrayElements(env,barr,JNI_FALSE);

     if(alen   >   0)

     {

      rtn   =   (char*)malloc(alen+1);         //"\0"

      memcpy(rtn,ba,alen);

      rtn[alen]=0;

     }

     (*env)->ReleaseByteArrayElements(env,barr,ba,0);  //

     return rtn;

}

 

JNIEXPORT jint JNICALL Java_com_example_ndkpassdata_DataProvider_add

  (JNIEnv * env, jobject jobject, jint x, jint y){

    // 想在logcat控制台上 打印日志

    LOGD("x=%d",x);

    LOGI("y=%d",y);

    // log.i(TAG,"sss");

    return x+y;

}

 

JNIEXPORT jstring JNICALL Java_com_example_ndkpassdata_DataProvider_sayHelloInC

  (JNIEnv * env, jobject jobject, jstring str){

 

    char* c="hello";

    // C语言中不能直接操作java中的字符串

    // java中的字符串转换成c语言中 char数组

    char* cstr=Jstring2CStr(env,str);

 

    strcat(cstr,c);

    LOGD("%s",cstr);

    return  (*env)->NewStringUTF(env,cstr);

}

 

JNIEXPORT jintArray JNICALL Java_com_example_ndkpassdata_DataProvider_intMethod

  (JNIEnv * env, jobject jobject, jintArray jarray){

    // jArray  遍历数组   jint*       (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);

    // 数组的长度    jsize       (*GetArrayLength)(JNIEnv*, jarray);

    // 对数组中每个元素 +5

    int length=(*env)->GetArrayLength(env,jarray);

    int* array=(*env)->GetIntArrayElements(env,jarray,0);

    int i=0;

    for(;i<length;i++){

       *(array+i)+=5;

    }

    return jarray;

}

其中,上面的代码中使用了NDK中打印日志的库,Log共享库库的位置在:

6 编写Android.mk文件,内容如下:

LOCAL_PATH := $(call my-dir)

 

include $(CLEAR_VARS)

 

#测试写了lib前缀的情况,如果不加lib,生成.so的时候回自动加上lib前缀

LOCAL_MODULE    := libhello

LOCAL_SRC_FILES := hello.c

 

#这里使用C语言打印日志,要引用log的共享库

#共享库的位置在:\android-ndk-r9d\platforms\android-19\arch-arm\usr\lib

LOCAL_LDLIBS    += -llog

 

include $(BUILD_SHARED_LIBRARY)

7 使用ndk-build进行交叉编译:

F5刷新项目,发现项目下多了:

8  编写布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    tools:context=".MainActivity" >

 

    <TextView

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_centerHorizontal="true"

        android:layout_centerVertical="true"

        android:text="@string/hello_world" />

 

    <Button

        android:onClick="click1"

        android:id="@+id/button1"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_alignParentTop="true"

        android:text="C语言实现第一个方法" />

 

    <Button

        android:onClick="click2"

        android:id="@+id/button2"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@+id/button1"

        android:text="C语言实现第二个方法" />

 

    <Button

         android:onClick="click3"

        android:id="@+id/button3"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@+id/button2"

        android:text="C语言实现第三个方法" />

 

</RelativeLayout>

9 编写Android清单文件:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.example.ndkpassdata"

    android:versionCode="1"

    android:versionName="1.0" >

 

    <uses-sdk

        android:minSdkVersion="8"

        android:targetSdkVersion="19" />

 

    <application

        android:allowBackup="true"

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name"

        android:theme="@style/AppTheme" >

        <activity

            android:name="com.example.ndkpassdata.MainActivity"

            android:label="@string/app_name" >

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

 

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

    </application>

 

</manifest>

接下来运行应用,就可以看到如下:

同时注意控制台,可以打印出日志信息。

 

 

 

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
23天前
|
ARouter Android开发
Android不同module布局文件重名被覆盖
Android不同module布局文件重名被覆盖
|
17天前
|
安全 Java 网络安全
Android远程连接和登录FTPS服务代码(commons.net库)
Android远程连接和登录FTPS服务代码(commons.net库)
16 1
|
21天前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
67 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
1月前
|
Ubuntu Shell API
Ubuntu 64系统编译android arm64-v8a 的openssl静态库libssl.a和libcrypto.a
Ubuntu 64系统编译android arm64-v8a 的openssl静态库libssl.a和libcrypto.a
|
2月前
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
在Android应用开发中,追求卓越性能是不变的主题。本文介绍如何利用Android NDK(Native Development Kit)结合Java与C++进行混合编程,提升应用性能。从环境搭建到JNI接口设计,再到实战示例,全面展示NDK的优势与应用技巧,助你打造高性能应用。通过具体案例,如计算斐波那契数列,详细讲解Java与C++的协作流程,帮助开发者掌握NDK开发精髓,实现高效计算与硬件交互。
110 1
|
1月前
|
ARouter Android开发
Android不同module布局文件重名被覆盖
Android不同module布局文件重名被覆盖
94 0
|
3月前
|
存储 监控 数据库
Android经典实战之OkDownload的文件分段下载及合成原理
本文介绍了 OkDownload,一个高效的 Android 下载引擎,支持多线程下载、断点续传等功能。文章详细描述了文件分段下载及合成原理,包括任务创建、断点续传、并行下载等步骤,并展示了如何通过多种机制保证下载的稳定性和完整性。
94 0
|
7天前
|
编解码 Java Android开发
通义灵码:在安卓开发中提升工作效率的真实应用案例
本文介绍了通义灵码在安卓开发中的应用。作为一名97年的聋人开发者,我在2024年Google Gemma竞赛中获得了冠军,拿下了很多项目竞赛奖励,通义灵码成为我的得力助手。文章详细展示了如何安装通义灵码插件,并通过多个实例说明其在适配国际语言、多种分辨率、业务逻辑开发和编程语言转换等方面的应用,显著提高了开发效率和准确性。
|
6天前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
19 5
|
4天前
|
JSON Java Android开发
探索安卓开发之旅:打造你的第一个天气应用
【10月更文挑战第30天】在这个数字时代,掌握移动应用开发技能无疑是进入IT行业的敲门砖。本文将引导你开启安卓开发的奇妙之旅,通过构建一个简易的天气应用来实践你的编程技能。无论你是初学者还是有一定经验的开发者,这篇文章都将成为你宝贵的学习资源。我们将一步步地深入到安卓开发的世界中,从搭建开发环境到实现核心功能,每个环节都充满了发现和创造的乐趣。让我们开始吧,一起在代码的海洋中航行!