1.程序正常,但是找不到串口
adb root && adb remount && adb shell
cd dev
setenforce 0
2.接收不到数据
修改serialport.c文件,加入两句代码:
ioctl(fd, 0x544d);
ioctl(descriptor, 0x544e);
具体加的位置如下图所示:
/*
* Copyright 2009-2011 Cedric Priscal
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <jni.h>
#include "SerialPort.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;
}
}
/*
* Class: android_serialport_SerialPort
* Method: open
* Signature: (Ljava/lang/String;II)Ljava/io/FileDescriptor;
*/
JNIEXPORT jobject JNICALL Java_android_1serialport_1api_SerialPort_open
(JNIEnv *env, jclass thiz, jstring path, jint baudrate, jint stopBits, jint dataBits,
jint parity, jint flowCon, jint flags) {
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(env, 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(env, 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);
ioctl(fd, 0x544d);
cfg.c_cflag &= ~CSIZE;
switch (dataBits) {
case 5:
cfg.c_cflag |= CS5; //使用5位数据位
break;
case 6:
cfg.c_cflag |= CS6; //使用6位数据位
break;
case 7:
cfg.c_cflag |= CS7; //使用7位数据位
break;
case 8:
cfg.c_cflag |= CS8; //使用8位数据位
break;
default:
cfg.c_cflag |= CS8;
break;
}
switch (parity) {
case 0:
cfg.c_cflag &= ~PARENB; //无奇偶校验
break;
case 1:
cfg.c_cflag |= (PARODD | PARENB); //奇校验
break;
case 2:
cfg.c_iflag &= ~(IGNPAR | PARMRK); // 偶校验
cfg.c_iflag |= INPCK;
cfg.c_cflag |= PARENB;
cfg.c_cflag &= ~PARODD;
break;
default:
cfg.c_cflag &= ~PARENB;
break;
}
switch (stopBits) {
case 1:
cfg.c_cflag &= ~CSTOPB; //1位停止位
break;
case 2:
cfg.c_cflag |= CSTOPB; //2位停止位
break;
default:
break;
}
// hardware flow control
switch (flowCon) {
case 0:
cfg.c_cflag &= ~CRTSCTS; //不使用流控
break;
case 1:
cfg.c_cflag |= CRTSCTS; //硬件流控
break;
case 2:
cfg.c_cflag |= IXON | IXOFF | IXANY; //软件流控
break;
default:
cfg.c_cflag &= ~CRTSCTS;
break;
}
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(env, "java/io/FileDescriptor");
jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "<init>", "()V");
jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");
mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);
(*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint) fd);
}
return mFileDescriptor;
}
/*
* Class: cedric_serial_SerialPort
* Method: close
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_android_1serialport_1api_SerialPort_close
(JNIEnv *env, jobject thiz) {
jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");
jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I");
jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);
jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);
ioctl(descriptor, 0x544e);
LOGD("close(fd = %d)", descriptor);
close(descriptor);
}
3.通过Android studio的run apk按钮可以安装成功apk,但是生成的串口工具给别人安装,却闪退。
原因是安装完串口app没有赋予系统权限。此时需要系统签名。
(1)修改AndroidManifest.xml文件,加入android.uid.system权限。注意此代码加载的位置
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ysn.serialport"
android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:requestLegacyExternalStorage="true">
<activity android:name=".MainActivity" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
(2)使用Android studio自带工具进行签名。Build--Generate Signed Bundle /apk--选择APK--点击NEXT--如果没有keystore,点击Create new,填写其中的内容,如果已有keystore,点击choose existing,然后填写key store password、key alias、key password,然后点击next,选择debug,选择V1和V2,然后点击finish。等待编译完成,最后生成的签名好的apk,放在app--debug目录下,名为app-debug.apk(此apk完成了系统签名)。将此apk拖到应用界面即可完成安装,也可以将此apk分享给其他人进行安装。
注意,此时如果用Android studio 的run app按钮,往往无法安装成功。这给调试带来麻烦。因此需要加上步骤(3),方便调试。
(3)在build.gradle(:app)文件中配置签名。
apply plugin: 'com.android.application'
android {
compileSdkVersion 30
defaultConfig {
applicationId "com.ysn.serialport"
minSdkVersion 26
targetSdkVersion 30
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
buildToolsVersion '30.0.2'
signingConfigs {
debug {
storeFile file('release.keystore')
storePassword '123qwe'
keyAlias 'androidreleasekey'
keyPassword '123qwe'
}
release {
storeFile file('release.keystore')
storePassword '123qwe'
keyAlias 'androidreleasekey'
keyPassword '123qwe'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.42'
implementation project(':serialport')
implementation 'tp.xmaihh:serialport:2.0'
implementation 'pub.devrel:easypermissions:1.2.0'
}
注意,完成(1)(2)(3)步骤后,可以使用Android studio 的run app按钮可以安装成功,方便调试,但是无法在app下生成debug文件夹,在build--output--apk--debug中生成的apk也无法给其他人进行安装。