网上很多的JNI文章,几乎都是讲的编译成 .SO 几动态库文件,对于编译成可执行文件的很少,然而对编译成可执行文件几乎就是官方文档中的例子,这几天为了项目,自己做了小实验,特记录一下:
首先看一下目录结构:
首先看Android.mk 的内容
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := io
LOCAL_SRC_FILES := io.c
include $(BUILD_EXECUTABLE)
首先申明,由于是自己的测试,所以代码写得很丑哦!!!!
io.c 的代码:(为了工程的需要我这里测试的在线程中读写直接在主函数中也可)
<c程序编译后一定要将libs里面的名为io 的可执行文件拷贝到assets目录里面>
/*
* io.c
*
* Created on: 2014年1月22日
* Author: Jason
*/
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *start_routine (void *arg)
{
while (1)
{
char buf[128] = { 0 };
printf("please enter input .... \n");
fflush(stdout);
fgets(buf,128,stdin);
printf("copy : %s\n", buf);
fflush(stdout);
if(0 == strcmp(buf,"BREAK"))
break;
memset(buf,0,128);
}
}
int main()
{
pthread_t thread;
if( 0 > pthread_create(&thread, NULL,start_routine, NULL))
{
printf("pthread_create failed \n");
}
pthread_join(thread,NULL);
return 0;
}
---------------------------------------------------------------------------------------------------------------------------------------------------------
android部分
---------------------------------------------------------------------------------------------------------------------------------------------------------
1、布局
<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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView"
android:background="#bfbfbfbf"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/editText1"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:textColor="#003399"
android:textSize="22sp"
android:text="@string/hello_world" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/button2"
android:layout_alignBottom="@+id/button2"
android:layout_alignLeft="@+id/textView"
android:layout_marginLeft="37dp"
android:text="读" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignRight="@+id/textView"
android:layout_marginBottom="67dp"
android:layout_marginRight="24dp"
android:text="写" />
<EditText
android:id="@+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/button1"
android:layout_alignLeft="@+id/textView"
android:layout_alignRight="@+id/textView"
android:layout_marginBottom="96dp"
android:ems="10" />
</RelativeLayout>
2、JAVA部分
package com.example.jniio;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import android.os.Bundle;
import android.app.Activity;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends Activity
{
private static final String TAG = "CALLJNI";
private TextView textView = null;
private Button readButton = null;
private Button writeButton = null;
private EditText editText = null;
private Process process = null;
private PackageInfo mPInfo = null;
private String text = "";
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init(); // ----- 实例化组件
copyApplication("io"); //加载可执行文件
//开线程,不阻碍ui线程
new Thread(new Runnable()
{
@Override
public void run()
{
try
{
//调用程序
Log.i(TAG, "process action .... ");
process = new ProcessBuilder().directory(new File(mPInfo.applicationInfo.dataDir)).redirectErrorStream(true).command("./io").start();
Log.i(TAG, "process actioned ");
}
catch (IOException e1)
{
e1.printStackTrace();
Log.e(TAG, "process wrong !!! ");
}
}
}).start();
}
/**
* 初始化 ---- 实例化
*/
private void init()
{
this.textView = (TextView) findViewById(R.id.textView);
this.readButton = (Button) findViewById(R.id.button1);
this.writeButton = (Button) findViewById(R.id.button2);
this.editText = (EditText) findViewById(R.id.editText1);
try
{
mPInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
}
catch (NameNotFoundException e2)
{
Log.e(TAG, "mPInfo wrong !!! ");
e2.printStackTrace();
}
textView.setText(text);
readButton.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
text += "<<<: "+read()+"\n";
Log.i(TAG, "<<< 读 : "+text);
textView.setText(text);
}
});
writeButton.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
String inputString = editText.getText().toString();
Log.i(TAG, "<<< 写 : "+inputString);
write(inputString+"\n");
text += ">>>: "+inputString +"\n";
textView.setText(text);
editText.setText("");
}
});
}
/**
* 写
*
* @param string
*/
public void write(String string)
{
Log.i(TAG, ">>>:write .... "+string);
if (process != null)
{
try
{
OutputStream out = process.getOutputStream();
BufferedWriter bWriter = new BufferedWriter(new OutputStreamWriter(out));
bWriter.write(string);
bWriter.flush();
Log.i(TAG, ">>>:write OK! ");
}
catch (Exception e)
{
// TODO: handle exception
}
}
}
/**
* 读
*/
public String read()
{
String outpString = null;
try
{
InputStream in = process.getInputStream();
BufferedReader bReader = new BufferedReader(new InputStreamReader(in));
outpString = bReader.readLine();
Log.i(TAG, "<<<:read() .... "+outpString);
}
catch (Exception e)
{
// TODO: handle exception
}
return outpString;
}
/**
* android 不会加载除 .so的文件,所以对于可执行文件就得自己手动加载 我把可执行文件拷贝到 assets目录下,在程序运行时,在加载到运行的空间。
*
* @param applicationName 可执行程序名
*/
public void copyApplication(String applicationName)
{
try
{
PackageInfo mPInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
try
{
File of = new File(mPInfo.applicationInfo.dataDir + "/" + applicationName);
InputStream in = getAssets().open(applicationName);
OutputStream out = new FileOutputStream(of);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0)
{
out.write(buf, 0, len);
}
in.close();
out.close();
Log.v(TAG, "copied " + applicationName);
}
catch (Exception e)
{
Log.e(TAG, "Error: Could not find " + applicationName, e);
throw new Exception("Cannot find " + applicationName + " in assets.");
}
Log.v(TAG, "setting executable flag");
Process process = new ProcessBuilder().directory(new File(mPInfo.applicationInfo.dataDir)).redirectErrorStream(true).command("chmod", "777", "./" + applicationName).start();
process.waitFor();
int rvalue = process.exitValue();
Log.v(TAG, "chmod returned : " + rvalue);
if (rvalue != 0)
{
Log.v(TAG, "cannot set executable flag");
throw new Exception("Cannot set executable flag.");
}
}
catch (Exception e)
{
Log.e(TAG, "could not set up " + applicationName, e);
}
}
@Override
protected void onDestroy()
{
write("BREAK\n");
super.onDestroy();
}
}