android studio更新换代后2.2后开发后开发ndk方便了很多。接下来以串口为例做一发ndk开发
1.集成ndk环境:
重点是C++呢里打勾,然后一路Next到finsh
然后Android studio就自动集成好了ndk,就这么简单
这是新增的CMake生成的ndk环境目录
这里只讲使用 不讲原理,所以想知道原理的话可自行百度CMake,有很全的介绍
MyApplication.class
import android.app.Application;
import com.example.sjs.vendingmachine.SerialUtil.SerialPort;
import com.example.sjs.vendingmachine.SerialUtil.SerialPortFinder;
import java.io.File;
import java.io.IOException;
import java.security.InvalidParameterException;
/**
* Created by kqw on 2016/10/26.
* MyApplication
*/
public class MyApplication extends Application {
private static final String TAG = "MyApplication";
public SerialPortFinder mSerialPortFinder = new SerialPortFinder();
private SerialPort mSerialPort = null;
public SerialPort getSerialPort() throws SecurityException, IOException, InvalidParameterException {
if (mSerialPort == null) {
mSerialPort = new SerialPort(new File("/dev/ttyUSB0"),9600 , 0);
}
return mSerialPort;
}
public void closeSerialPort() {
if (mSerialPort != null) {
mSerialPort.close();
mSerialPort = null;
}
}
}
在Manifest.xml里,添加权限,添加MyApplication声明
<!-- 往sdcard中写入数据的权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 在sdcard中创建/删除文件的权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
android:name=".Application.MyApplication"
SerialPort.class
import android.util.Log;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class SerialPort {
private static final String TAG = "SerialPort";
/*
* Do not remove or rename the field mFd: it is used by native method close();
*/
private FileDescriptor mFd;
private FileInputStream mFileInputStream;
private FileOutputStream mFileOutputStream;
public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException {
/* Check access permission */
if (!device.canRead() || !device.canWrite()) {
try {
/* Missing read/write permission, trying to chmod the file */
Process su;
su = Runtime.getRuntime().exec("/system/xbin/su");
String cmd = "chmod 666 " + device.getAbsolutePath() + "\n"
+ "exit\n";
su.getOutputStream().write(cmd.getBytes());
if ((su.waitFor() != 0) || !device.canRead()
|| !device.canWrite()) {
throw new SecurityException();
}
} catch (Exception e) {
e.printStackTrace();
throw new SecurityException();
}
}
mFd = open(device.getAbsolutePath(), baudrate, flags);
if (mFd == null) {
Log.e(TAG, "native open returns null");
throw new IOException();
}
mFileInputStream = new FileInputStream(mFd);
mFileOutputStream = new FileOutputStream(mFd);
}
// Getters and setters
public InputStream getInputStream() {
return mFileInputStream;
}
public OutputStream getOutputStream() {
return mFileOutputStream;
}
// JNI
private native static FileDescriptor open(String path, int baudrate, int flags);
public native void close();
static {
System.loadLibrary("native-lib");
// System.loadLibrary("serial_port");
}
}
open,close方法标红时右键 空格,自动生成相关联的c++方法
SerialPortActivity.class
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import com.example.sjs.vendingmachine.Application.MyApplication;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidParameterException;
public abstract class SerialPortActivity extends Activity {
protected MyApplication mApplication;
protected SerialPort mSerialPort;
protected OutputStream mOutputStream;
private InputStream mInputStream;
private ReadThread mReadThread;
HandlerThread sendingHandlerThread = new HandlerThread("sendingHandlerThread");
{
sendingHandlerThread.start();
}
protected Handler sendingHandler = new Handler(sendingHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
if (mOutputStream != null) {
try {
mOutputStream.write((byte[]) msg.obj);
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
private class ReadThread extends Thread {
@Override
public void run() {
super.run();
while (!isInterrupted()) {
int size;
try {
byte[] buffer = new byte[64];
if (mInputStream == null) return;
size = mInputStream.read(buffer);
if (size > 0) {
onDataReceived(buffer, size);
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
}
private void DisplayError(String resourceId) {
AlertDialog.Builder b = new AlertDialog.Builder(this);
b.setTitle("Error");
b.setMessage(resourceId);
b.setPositiveButton("OK", new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
SerialPortActivity.this.finish();
}
});
b.show();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mApplication = (MyApplication) getApplication();
try {
mSerialPort = mApplication.getSerialPort();
mOutputStream = mSerialPort.getOutputStream();
mInputStream = mSerialPort.getInputStream();
/* Create a receiving thread */
mReadThread = new ReadThread();
mReadThread.start();
} catch (SecurityException e) {
// You do not have read/write permission to the serial port.
DisplayError("You do not have read/write permission to the serial port.");
} catch (IOException e) {
// The serial port can not be opened for an unknown reason.
DisplayError("The serial port can not be opened for an unknown reason.");
} catch (InvalidParameterException e) {
// Please configure your serial port first.
DisplayError("Please configure your serial port first.");
}
}
protected abstract void onDataReceived(final byte[] buffer, final int size);
@Override
protected void onDestroy() {
if (mReadThread != null)
mReadThread.interrupt();
mApplication.closeSerialPort();
mSerialPort = null;
if (null != sendingHandlerThread) {
sendingHandlerThread.quit();
}
super.onDestroy();
}
}
SerialPortFinder.class
import android.util.Log;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.Iterator;
import java.util.Vector;
public class SerialPortFinder {
public class Driver {
public Driver(String name, String root) {
mDriverName = name;
mDeviceRoot = root;
}
private String mDriverName;
private String mDeviceRoot;
Vector<File> mDevices = null;
public Vector<File> getDevices() {
if (mDevices == null) {
mDevices = new Vector<File>();
File dev = new File("/dev");
File[] files = dev.listFiles();
int i;
for (i=0; i<files.length; i++) {
if (files[i].getAbsolutePath().startsWith(mDeviceRoot)) {
Log.d(TAG, "Found new device: " + files[i]);
mDevices.add(files[i]);
}
}
}
return mDevices;
}
public String getName() {
return mDriverName;
}
}
private static final String TAG = "SerialPort";
private Vector<Driver> mDrivers = null;
Vector<Driver> getDrivers() throws IOException {
if (mDrivers == null) {
mDrivers = new Vector<Driver>();
LineNumberReader r = new LineNumberReader(new FileReader("/proc/tty/drivers"));
String l;
while((l = r.readLine()) != null) {
// Issue 3:
// Since driver name may contain spaces, we do not extract driver name with split()
String drivername = l.substring(0, 0x15).trim();
String[] w = l.split(" +");
if ((w.length >= 5) && (w[w.length-1].equals("serial"))) {
Log.d(TAG, "Found new driver " + drivername + " on " + w[w.length-4]);
mDrivers.add(new Driver(drivername, w[w.length-4]));
}
}
r.close();
}
return mDrivers;
}
public String[] getAllDevices() {
Vector<String> devices = new Vector<String>();
// Parse each driver
Iterator<Driver> itdriv;
try {
itdriv = getDrivers().iterator();
while(itdriv.hasNext()) {
Driver driver = itdriv.next();
Iterator<File> itdev = driver.getDevices().iterator();
while(itdev.hasNext()) {
String device = itdev.next().getName();
String value = String.format("%s (%s)", device, driver.getName());
devices.add(value);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return devices.toArray(new String[devices.size()]);
}
public String[] getAllDevicesPath() {
Vector<String> devices = new Vector<String>();
// Parse each driver
Iterator<Driver> itdriv;
try {
itdriv = getDrivers().iterator();
while(itdriv.hasNext()) {
Driver driver = itdriv.next();
Iterator<File> itdev = driver.getDevices().iterator();
while(itdev.hasNext()) {
String device = itdev.next().getAbsolutePath();
devices.add(device);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return devices.toArray(new String[devices.size()]);
}
}
最后调用的activity
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.example.sjs.vendingmachine.SerialUtil.SerialPortActivity;
public class OpenDoorActivity extends SerialPortActivity {
private static String TAG = "MainActivity";
// private EditText mEditTextEmission;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_open_door);
}
public void send(int open_num) {
// 参数是字符串
// String text = mEditTextEmission.getText().toString();
// if (TextUtils.isEmpty(text )) {
// return;
// }
// Message message = Message.obtain();
// message.obj = text .getBytes();
// Log.i(TAG,HxStr+"send已发送");
// sendingHandler.sendMessage(message);
//收到参数已被封装
Log.i(TAG,open_num+"send已发送open_num");
byte [] HxStr =hex2byte(open_numarr[open_num]);
Message message = Message.obtain();
message.obj = HxStr;
Log.i(TAG,HxStr+"send已发送");
sendingHandler.sendMessage(message);
}
@Override
protected void onDataReceived(final byte[] buffer, final int size) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(mApplication, "收到消息:" + new String(buffer) + " size = " + size, Toast.LENGTH_SHORT).show();
}
});
}
}
/**
* @Title:hex2byte
* @Description:字符串转16进制
* @param hex
* 字符串
* @return 16进制字符串
* @throws
*/
public static byte[] hex2byte(String hex) {
String digital = "0123456789ABCDEF";
String hex1 = hex.replace(" ", "");
char[] hex2char = hex1.toCharArray();
byte[] bytes = new byte[hex1.length()/2];
byte temp;
for (int p = 0; p < bytes.length; p++) {
temp = (byte) (digital.indexOf(hex2char[2 * p]) * 16);
temp += digital.indexOf(hex2char[2 * p + 1]);
bytes[p] = (byte) (temp & 0xff);
}
return bytes;
}
/**
* 数组转换成十六进制字符串
*
* @return HexString
*/
public static final String bytesToHexString(byte[] bArray) {
StringBuffer sb = new StringBuffer(bArray.length);
String sTemp;
for (int i = 0; i < bArray.length; i++) {
sTemp = Integer.toHexString(0xFF & bArray[i]);
if (sTemp.length() < 2)
sb.append(0);
sb.append(sTemp.toUpperCase());
}
return sb.toString();
}
/**
* @Title:bytes2HexString
* @Description:字节数组转16进制字符串
* @param b
* 字节数组
* @return 16进制字符串
* @throws
*/
public static String bytes2HexString(byte[] b) {
StringBuffer result = new StringBuffer();
String hex;
for (int i = 0; i < b.length; i++) {
hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
result.append(hex.toUpperCase());
}
return result.toString();
}
}
native-lib.cpp
#include <jni.h>
#include <string>
extern "C" {
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "android/log.h"
static const char *TAG = "serial_port";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)
static speed_t getBaudrate(jint baudrate) {
switch (baudrate) {
case 0:
return B0;
case 50:
return B50;
case 75:
return B75;
case 110:
return B110;
case 134:
return B134;
case 150:
return B150;
case 200:
return B200;
case 300:
return B300;
case 600:
return B600;
case 1200:
return B1200;
case 1800:
return B1800;
case 2400:
return B2400;
case 4800:
return B4800;
case 9600:
return B9600;
case 19200:
return B19200;
case 38400:
return B38400;
case 57600:
return B57600;
case 115200:
return B115200;
case 230400:
return B230400;
case 460800:
return B460800;
case 500000:
return B500000;
case 576000:
return B576000;
case 921600:
return B921600;
case 1000000:
return B1000000;
case 1152000:
return B1152000;
case 1500000:
return B1500000;
case 2000000:
return B2000000;
case 2500000:
return B2500000;
case 3000000:
return B3000000;
case 3500000:
return B3500000;
case 4000000:
return B4000000;
default:
return -1;
}
}
JNIEXPORT jobject JNICALL
Java_com_example_sjs_vendingmachine_SerialUtil_SerialPort_open(JNIEnv *env, jclass type,
jstring path, jint baudrate,
jint flags) {
// const char *path = env->GetStringUTFChars(path_, 0);
//
// // TODO
//
// env->ReleaseStringUTFChars(path_, path);
int fd;
speed_t speed;
jobject mFileDescriptor;
/* Check arguments */
{
speed = getBaudrate(baudrate);
if (speed == -1) {
/* TODO: throw an exception */
LOGE("Invalid baudrate");
return NULL;
}
}
/* Opening device */
{
jboolean iscopy;
const char *path_utf = env->GetStringUTFChars(path, &iscopy);
LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);
fd = open(path_utf, O_RDWR | flags);
LOGD("open() fd = %d", fd);
env->ReleaseStringUTFChars(path, path_utf);
if (fd == -1) {
/* Throw an exception */
LOGE("Cannot open port");
/* TODO: throw an exception */
return NULL;
}
}
/* Configure device */
{
struct termios cfg;
LOGD("Configuring serial port");
if (tcgetattr(fd, &cfg)) {
LOGE("tcgetattr() failed");
close(fd);
/* TODO: throw an exception */
return NULL;
}
cfmakeraw(&cfg);
cfsetispeed(&cfg, speed);
cfsetospeed(&cfg, speed);
if (tcsetattr(fd, TCSANOW, &cfg)) {
LOGE("tcsetattr() failed");
close(fd);
/* TODO: throw an exception */
return NULL;
}
}
/* Create a corresponding file descriptor */
{
jclass cFileDescriptor = env->FindClass("java/io/FileDescriptor");
jmethodID iFileDescriptor = env->GetMethodID(cFileDescriptor, "<init>", "()V");
jfieldID descriptorID = env->GetFieldID(cFileDescriptor, "descriptor", "I");
mFileDescriptor = env->NewObject(cFileDescriptor, iFileDescriptor);
env->SetIntField(mFileDescriptor, descriptorID, (jint) fd);
}
return mFileDescriptor;
}
JNIEXPORT void JNICALL
Java_com_example_sjs_vendingmachine_SerialUtil_SerialPort_close(JNIEnv *env, jobject instance) {
// TODO
}
extern "C"
jstring
Java_com_example_sjs_vendingmachine_MainActivity_stringFromJNI(
JNIEnv *env,
jobject thiz) {
// TODO
jclass SerialPortClass = env->GetObjectClass(thiz);
jclass FileDescriptorClass = env->FindClass((char *) "java/io/FileDescriptor");
jfieldID mFdID = env->GetFieldID(SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
jfieldID descriptorID = env->GetFieldID(FileDescriptorClass, "descriptor", "I");
jobject mFd = env->GetObjectField(thiz, mFdID);
jint descriptor = env->GetIntField(mFd, descriptorID);
LOGD("close(fd = %d)", descriptor);
close(descriptor);
}
}
哦了