android 编译调用C代码

博客地址:www.zalezone.cn



前言

需求来源

这几天帮别人做一个简单的androidclient,也没什么功能。主要就是调用C代码来对手机的Wifi网络进行设置,于是也就引出了技术难点所在。怎样去调用C程序达到我们所须要的效果。

解决方式

对于这个。我想出了两种解决方式:

  1. 第一种方案是利用JNI来进行本地调用。关于什么是JNI呢。JNI事实上是Java Native Interface的简称。也就是java本地接口,它提供了若干API实现了java和其它语言的通信(主要是C和C++)。

  2. 另外一种方法是将要运行的C代码编译成可运行文件,然后将这个可运行文件和程序一起打包成APK,在须要使用的时候调用这个可运行文件。

终于选择

最后我选择了另外一种方案,理由是另外一种方法在我已经有了可运行文件的条件下整体来说比較简单。可操作性强。而第一种方案的话由于还要下载android的NDK,NDK是一系列工具的集合,提供了帮助开发人员高速开发C或则C++的动态库,并能自己主动将so和java应用一起打包成apk,十分方便。

技术实现

可运行文件

首先须要得到一个可运行文件。当然想要的到可运行文件并非想象中的那么简单,不是在linux中直接gcc就能到的,这里须要对C代码进行交叉编译获得能够在android机子上运行的可运行文件,详细怎样对C文件进行交叉编译,这里就不再赘述。大家能够上网查找一下。

另外,NDK也是个不错的工具。

资源存储

这里的资源存储页算是个小坑。寻常我们在写java程序的时候,假设要打开一个文件的话就直接输入路径。比方假设所要使用的文件就在项目的文件夹下,直接输入文件名称就能够调用了,可是这里的执行环境是嵌入式设备,不是PC,这就涉及到一个问题,资源怎样存储了。

这里先谈一下Android中的asset目录res/raw目录的异同:

  • 同样点
    • 两者文件夹下的文件在打包后都会原封不动的保存在apk包中,不会被编译成二进制。

  • 不同点
    • res/raw中的文件会被映射到R.java中。訪问的时候直接使用资源ID就可以。而assets文件夹下的文件不会被映射到R.java。

    • res/raw不能够有文件夹结构,而assets文件夹下能够再建立文件夹。

资源获取

这里顺带说一下res/raw下的文件资源的读取方法,通过下面方式获取输入流来进行写操作

1
InputStream is =getResources().openRawResource(R.id.filename);

接下来才是我用到的读取assets下的方法。相同也是通过获取输入流的方式来进行写操作

1
2
3
AssetManager am = null;
am = getAssets();
InputStream is = am.open("filename");

注意点:据说Assert仅仅能放单个文件不超过1M的文件。可是不是真的详细还没考证过。假设碰到问题了应该考虑一下这个注意点。

尽管读取是成功了,可是要用shell脚本运行的话,应该在手机的存储上应该有这个文件,光是读取的话在手机里面是找不见的,所以我们须要一个存文件的操作。

这里我写了一个存文件的函数。当中将获取assets中数据的方法也结合进去了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void copyDataToSD(String outFileName)throws IOException
{
InputStream myInputStream;
OutputStream myOutputStream = new FileOutputStream(outFileName);
myInputStream = this.getAssets().open("a.out");
byte[] buffer = new byte[1024];
int length = myInputStream.read(buffer);
while (length > 0) {
myOutputStream.write(buffer, 0, length);
length = myInputStream.read(buffer);
}
myOutputStream.flush();
myInputStream.close();
myOutputStream.close();
}

然后我定义的传入的outFileName是定义的文件路径加文件名称

1
2
private static String EXE_PATH = "data/data/com.example.g3wifi/a.out";
private static File exe_file;

shell命令运行

到这里的话就是“万事俱备。仅仅欠东风”了,我们须要运行所得到的可运行文件。由于android是基于linux的。所以一些主要的命令还是支持的,在android中要运行shell命令的话就按例如以下格式就可以:

1
2
3
4
5
6
7
8
public void exeC(String cmd)throws IOException
{
Runtime runtime =Runtime.getRuntime();
Process process = runtime.exec(cmd);
//Process process = runtime.exec(new String[]{"su","reboot"});//能够运行两条命令
//这能够得到运行shell命令后的结果
BufferedReader ie = new BufferedReader(new InputStreamReader(process.getErrorStream()));
}





posted @ 2017-06-06 19:11  mfmdaoyou  阅读(1688)  评论(0编辑  收藏  举报