• Android jni 编程入门


      本文将介绍如何使用eclipse和ndk-build来编写一个基于Android4.4版本的包含有.so动态库的安卓程序。

      前提是已经安装和配置好了诸如SDK,NDK等编译环境。下面开始编程!

    1 程序逻辑

      我们要编写的程序包含两部分:java部分——负责界面和调用JNI native函数;JNI native 部分——负责native函数的具体实现(本文使用C语言)。

      native 函数伪代码如下:

    /*
    funtion: 传入两个整形变量,计算他们之和
    return : 返回字符串“The result is ” +sum
    */
    char*  test(int fisrt, int second){
         sum = first + scond;
         return “The result is ” +sum; 
    }
    

    2 程序实现

    2.1 创建项目

       如编写普通apk一样创建一个apk项目。然后在该项目的根目录添加一个文件夹 jni,然后在这个文件夹下面添加hello.c和Android.mk两个文件,完成效果如下图所示:

      

    2.2 开始JNI编程

        hello.c代码如下:

     /*hello.c*/
    1
    #include <string.h> 2 #include <stdio.h> 3 #include <jni.h> 4 5 //一定不要忘了 JNIEXPORT关键字! 6 JNIEXPORT jstring Java_com_wan_firstjniprogram_MainActivity_test( JNIEnv* env, 7 jobject thiz , jint first, jint second) 8 { 9 #if defined(__arm__) 10 #if defined(__ARM_ARCH_7A__) 11 #if defined(__ARM_NEON__) 12 #define ABI "armeabi-v7a/NEON" 13 #else 14 #define ABI "armeabi-v7a" 15 #endif 16 #else 17 #define ABI "armeabi" 18 #endif 19 #elif defined(__i386__) 20 #define ABI "x86" 21 #elif defined(__mips__) 22 #define ABI "mips" 23 #else 24 #define ABI "unknown" 25 #endif 26 27 const char* format = "The result is %d "; 28 char *ret; 29 //add two values 30 jint sum = first + second; 31 //malloc room for the ret 32 ret = malloc(sizeof(format) + 20); 33 //standard sprintf 34 sprintf(ret, format, sum); 35 jstring stringRet = (*env)->NewStringUTF(env, ret); 36 free(ret); 37 return stringRet; 38 }

        关于JNI函数名的编写,网上有很多资料,这里主要提醒两点:1、包名需要全小写,类名和函数名要大小写一致;2、一定要在函数名前加上关键字 JNIEXPORT 。

        再来编写Android.mk,代码如下:

    1 LOCAL_PATH := $(call my-dir)
    2 
    3 include $(CLEAR_VARS)
    4 
    5 LOCAL_MODULE    := hello
    6 LOCAL_SRC_FILES := hello.c
    7 
    8 include $(BUILD_SHARED_LIBRARY)

        如何编写Android.mk就不过多解释了,网上资料也是一大堆,这里直接给出代码。

        现在,我们的JNI 编写代码部分算是结束了,就还剩下最后一步——编译。编译很简单:使用cmd命令行进入你的apk工程所在的文件夹的jni目录(我的目录是D:androidWorkSpacefirstJniProgramjni),然后输入ndk-build命令即可自动编译,结果如下图所示:

       从上图可以看出,我们已经成功生成了libhello.so库。到这里,JNI编程部分已经完结。下面就是进入JAVA部分了。

    2.2 java编写

       如何编写界面我就不多说了,这里指出我所遇到的一个问题。

       问题:由于Android4.4的apk项目会创建两个layout.xml布局文件,如下图所示:

    且首先展示给developer的是fragment_main.xml。这同Android2.3.3是不一样的(默认只有一个布局文件——activity_main.xml)!所以如果要添加组件的话,最好添加到activity_main中,这样才不会发生各种activity错误~。

      activity_main.xml代码如下:

     1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     xmlns:tools="http://schemas.android.com/tools"
     3     android:id="@+id/container"
     4     android:layout_width="match_parent"
     5     android:layout_height="match_parent"
     6     tools:context="com.wan.firstjniprogram.MainActivity"
     7     tools:ignore="MergeRootFrame" >
     8     
     9     <TextView
    10         android:id="@+id/info"
    11         android:layout_width="wrap_content"
    12         android:layout_height="wrap_content"
    13         android:text="@string/hello_world" />
    14     <Button 
    15         android:id="@+id/button"
    16         android:layout_width="wrap_content"
    17         android:layout_height="wrap_content"
    18         android:text ="JNItest"/>
    19     
    20 </LinearLayout>

        下面展示MainActivity.java的代码:

     1 package com.wan.firstjniprogram;
     2 
     3 import junit.framework.Test;
     4 import android.support.v7.app.ActionBarActivity;
     5 import android.support.v7.app.ActionBar;
     6 import android.support.v4.app.Fragment;
     7 import android.R.string;
     8 import android.os.Bundle;
     9 import android.util.Log;
    10 import android.view.LayoutInflater;
    11 import android.view.Menu;
    12 import android.view.MenuItem;
    13 import android.view.View;
    14 import android.view.View.OnClickListener;
    15 import android.view.ViewGroup;
    16 import android.widget.Button;
    17 import android.widget.TextView;
    18 
    19 public class MainActivity extends ActionBarActivity {
    20     
    21     
    22     static{
    23         System.loadLibrary("hello");
    24     }
    25     
    26     public native String test(int first, int second); 
    27     
    28     private TextView info = null;
    29     private Button button = null;
    30 
    31     @Override
    32     protected void onCreate(Bundle savedInstanceState) {
    33         super.onCreate(savedInstanceState);
    34         setContentView(R.layout.activity_main);
    35 
    36         if (savedInstanceState == null) {
    37             getSupportFragmentManager().beginTransaction()
    38                     .add(R.id.container, new PlaceholderFragment())
    39                     .commit();
    40         }
    41         
    42         this.info = (TextView)super.findViewById(R.id.info);
    43         this.button = (Button)super.findViewById(R.id.button);
    44         
    45         this.button.setOnClickListener(new MyonclickListen());
    46         
    47     }
    48 
    49     private class MyonclickListen implements OnClickListener{
    50 
    51         @Override
    52         public void onClick(View arg0) {
    53             // TODO Auto-generated method stub
    54             //MainActivity.this.info.setText("123"/*test(1, 2)*/);
    55             int first = 1, second = 2;
    56             String ret = test(first, second);
    57             MainActivity.this.info.setText(ret);
    58         }
    59         
    60     }
    61     
    62     @Override
    63     public boolean onCreateOptionsMenu(Menu menu) {
    64         
    65         // Inflate the menu; this adds items to the action bar if it is present.
    66         getMenuInflater().inflate(R.menu.main, menu);
    67         return true;
    68     }
    69 
    70     @Override
    71     public boolean onOptionsItemSelected(MenuItem item) {
    72         // Handle action bar item clicks here. The action bar will
    73         // automatically handle clicks on the Home/Up button, so long
    74         // as you specify a parent activity in AndroidManifest.xml.
    75         int id = item.getItemId();
    76         if (id == R.id.action_settings) {
    77             return true;
    78         }
    79         return super.onOptionsItemSelected(item);
    80     }
    81 
    82     /**
    83      * A placeholder fragment containing a simple view.
    84      */
    85     public static class PlaceholderFragment extends Fragment {
    86 
    87         public PlaceholderFragment() {
    88         }
    89 
    90         @Override
    91         public View onCreateView(LayoutInflater inflater, ViewGroup container,
    92                 Bundle savedInstanceState) {
    93             View rootView = inflater.inflate(R.layout.fragment_main, container, false);
    94             return rootView;
    95         }
    96     }
    97 
    98 }

         OK!到此,整个程序的代码已经编写完毕,可以鼠标右击项目,run as->android application了。点击JNItest按钮后,效果如下图所示:

    3 修改

      如果需要修改hello.c文件,那么在修改完成后,同样的方式编译即可,无需其他操作。还有一点需要指出的是,程序在运行的时候,eclipse的DDMS的logcat会提示:

    NO JNIOnLoad....,这是一个warmming,是因为我们使用的javah方式编写native代码,而非使用jni_onload方式动态注册native函数,初学JNI编程可以不用理会。

      

      

  • 相关阅读:
    CrossApp alpha 0.1.10 发布,跨平台移动应用开发引擎
    CrossApp 0.1.8 发布,跨平台移动应用开发引擎
    CrossApp 0.1.6 发布,跨平台移动应用开发引擎
    【开源访谈】CrossApp作者栗元峰访谈实录
    CrossApp 0.1.5 发布,跨平台移动应用开发引擎
    java第一 ++--
    MySQL数据库
    JQ方法实用案例///鼠标移动到div和修改ipt中弹窗、CSS鼠标变小手、JQ获取元素属性、JQ选择器
    轮播图!!!!
    查找列表框、下拉菜单控件、对表格元素/表单控件进行增删改操作、创建元素并且复制节点与删除、 对表格操作、通用性和标准的事件监听方法(点击后弹窗效果以及去掉效果)
  • 原文地址:https://www.cnblogs.com/wanyuanchun/p/3762374.html
Copyright © 2020-2023  润新知