diff --git a/README.md b/README.md
index aa0afce..f54c0ec 100644
--- a/README.md
+++ b/README.md
@@ -1,51 +1,82 @@
# Android-SerialPort-API
+[Fork](https://code.google.com/archive/p/android-serialport-api/)自Google开源的Android串口通信Demo,修改成Android Studio项目
-[](https://jitpack.io/#licheedev/Android-SerialPort-API)
+This lib is a [fork](https://code.google.com/archive/p/android-serialport-api/) of the Android serial port communication Demo open sourced by Google.
-**Gradle 引用**
+## Installation & Usage
+**Gradle**
-1. 在根build.gradle中添加
+添加依赖:
+
+Add the dependency:
```
allprojects {
repositories {
...
- maven { url 'https://jitpack.io' }
+ jcenter()
+ mavenCentral() // since 2.1.3
}
}
-```
-
-2. 子module添加依赖
-```
dependencies {
- implementation 'com.github.licheedev:Android-SerialPort-API:2.0.0'
+ // 传统4KB内存页面版本
+ implementation 'com.licheedev:android-serialport:2.1.4'
+ // 适配16KB页面版本,https://developer.android.google.cn/guide/practices/page-sizes?hl=zh-cn
+ implementation 'com.licheedev:android-serialport:2.1.5'
}
```
-**修改`su`路径**
+**Import**
+
+```java
+import android.serialport.SerialPort;
+```
+
+**`su` path**
+
+In order to read/write to a serial port in Android you'll need `su` binary installed on device (this can be done by rooting the device). Usually Android devices that has the ability to communicate with serial ports have `su` installed on the default path `"/system/bin/su"`. To change this use:
```java
// su默认路径为 "/system/bin/su"
+// The default path of su is "/system/bin/su"
// 可通过此方法修改
+// If the path is different then change it using this
SerialPort.setSuPath("/system/xbin/su");
```
-**可选配置数据位、校验位、停止位**
-
-实现方式参考
-> https://juejin.im/post/5c010a19e51d456ac27b40fc
+**Usage**
```java
-
// 默认8N1(8数据位、无校验位、1停止位)
-SerialPort serialPort = SerialPort.newBuilder(path, baudrate).build();
-
-// 7E2(7数据位、偶校验、2停止位)
-SerialPort serialPort = SerialPort //
- .newBuilder(path, baudrate) // 串口地址地址,波特率
- .parity(2) // 校验位;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN)
- .dataBits(7) // 数据位,默认8;可选值为5~8
- .stopBits(2) // 停止位,默认1;1:1位停止位;2:2位停止位
+// Default 8N1 (8 data bits, no parity bit, 1 stop bit)
+SerialPort serialPort = new SerialPort(path, baudrate);
+
+// 可选配置数据位、校验位、停止位 - 7E2(7数据位、偶校验、2停止位)
+// or with builder (with optional configurations) - 7E2 (7 data bits, even parity, 2 stop bits)
+SerialPort serialPort = SerialPort
+ .newBuilder(path, baudrate)
+// 校验位;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN)
+// Check bit; 0: no check bit (NONE, default); 1: odd check bit (ODD); 2: even check bit (EVEN)
+// .parity(2)
+// 数据位,默认8;可选值为5~8
+// Data bit, default 8; optional value is 5~8
+// .dataBits(7)
+// 停止位,默认1;1:1位停止位;2:2位停止位
+// Stop bit, default 1; 1:1 stop bit; 2: 2 stop bit
+// .stopBits(2)
.build();
+
+// read/write to serial port - needs to be in different thread!
+InputStream in = serialPort.getInputStream();
+OutputStream out = serialPort.getOutputStream();
+
+// close
+serialPort.tryClose();
```
+
+实现方式参考
+
+Implementation reference
+1. Check [sample project](https://github.com/licheedev/Android-SerialPort-API/tree/master/sample)
+2. https://juejin.im/post/5c010a19e51d456ac27b40fc
diff --git a/build.gradle b/build.gradle
index 4b0c6dd..a47094e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,12 +4,13 @@ buildscript {
repositories {
google()
jcenter()
+ mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.1'
- classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
+ classpath 'com.android.tools.build:gradle:4.2.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
+ classpath 'org.jetbrains.dokka:dokka-gradle-plugin:1.4.32'
}
}
@@ -17,6 +18,7 @@ allprojects {
repositories {
google()
jcenter()
+ mavenCentral()
}
}
@@ -25,11 +27,11 @@ task clean(type: Delete) {
}
ext {
- compileSdkVersion = 28
+ compileSdkVersion = 29
minSdkVersion = 8
- targetSdkVersion = 28
+ targetSdkVersion = 29
- versionCode = 2
- versionName = "2.0.0"
+ versionCode = 3
+ versionName = "2.1.5"
}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index aa62a10..567806c 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -13,4 +13,6 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
#Mon Sep 18 19:30:46 CST 2017
+android.enableJetifier=true
+android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536m
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 8afa263..3ed5e54 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed Jul 03 10:00:36 CST 2019
+#Fri Sep 06 10:04:58 CST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
diff --git a/jitpack.gradle b/jitpack.gradle
deleted file mode 100644
index 3e87c62..0000000
--- a/jitpack.gradle
+++ /dev/null
@@ -1,30 +0,0 @@
-apply plugin: 'com.github.dcendents.android-maven'
-
-group = 'com.github.licheedev'
-
-tasks.withType(JavaCompile) {
- options.encoding = "UTF-8"
-}
-
-task sourcesJar(type: Jar) {
- from android.sourceSets.main.java.srcDirs
- classifier = 'sources'
-}
-
-task javadoc(type: Javadoc) {
- failOnError false
- source = android.sourceSets.main.java.sourceFiles
- classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
- classpath += configurations.compile
-}
-
-
-task javadocJar(type: Jar, dependsOn: javadoc) {
- classifier = 'javadoc'
- from javadoc.destinationDir
-}
-
-artifacts {
- archives sourcesJar
- archives javadocJar
-}
\ No newline at end of file
diff --git a/maven_publish.gradle b/maven_publish.gradle
new file mode 100644
index 0000000..e8a2281
--- /dev/null
+++ b/maven_publish.gradle
@@ -0,0 +1,130 @@
+// 依赖信息
+def groupIdDefined = "com.licheedev"
+def artifactIdDefined = "android-serialport"
+// 如果是测试版,版本号后面加上 -SNAPSHOT
+def versionDefined = rootProject.ext.versionName
+// 其他信息
+def gitUrl = "https://github.com/licheedev/Android-SerialPort-API"
+
+// 配置是否上传
+def toUpload = true
+
+//在根build.gradle中加入,最新版本号参考 https://github.com/Kotlin/dokka#using-dokka
+//classpath 'org.jetbrains.dokka:dokka-gradle-plugin:1.4.32'
+
+//在module的build.gradle末位加入
+//apply from: '../maven_publish.gradle'
+
+if (toUpload) {
+ apply plugin: 'signing'
+ apply plugin: 'maven-publish'
+ apply plugin: 'org.jetbrains.dokka'
+
+ //
+ // 打包源码
+ task sourcesJar(type: Jar) {
+ from android.sourceSets.main.java.srcDirs
+ classifier = 'sources'
+ }
+
+ task javadoc(type: Javadoc) {
+ failOnError false
+ source = android.sourceSets.main.java.sourceFiles
+ options {
+ encoding = "utf-8"
+ charSet 'UTF-8'
+ }
+ classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
+ classpath += configurations.compile
+ }
+
+ // 打包javadoc
+ task javadocJar(type: Jar, dependsOn: javadoc) {
+ classifier = 'javadoc'
+ from javadoc.destinationDir
+ }
+
+ // 打包包含kotlin源码的javadoc
+ task kotlinDocJar(type: Jar, dependsOn: dokkaHtml) {
+ classifier = 'javadoc'
+ from dokkaHtml.outputDirectory
+ }
+ //
+
+ afterEvaluate {
+
+ publishing {
+ publications {
+ mavenAndroid(MavenPublication) {
+ from components.release
+
+ groupId "$groupIdDefined"
+ artifactId "$artifactIdDefined"
+ version "$versionDefined"
+ // 上传source
+ artifact sourcesJar
+ // 上传javadoc
+ if (project.plugins.hasPlugin('kotlin-android')) {
+ artifact kotlinDocJar
+ } else {
+ artifact javadocJar
+ }
+
+ pom {
+ name = 'Android-SerialPort-API'
+ description = 'Android-SerialPort-API'
+ url = "$gitUrl"
+
+ //licenses {
+ // license {
+ // name = 'The MIT License'
+ // url = 'https://opensource.org/licenses/MIT'
+ // }
+ //}
+
+ licenses {
+ license {
+ name = 'The Apache License, Version 2.0'
+ url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
+ }
+ }
+
+ developers {
+ developer {
+ id = 'licheedev'
+ name = 'John Lee'
+ email = 'licheedev@foxmail.com'
+ }
+ }
+ scm {
+ connection = "$gitUrl"
+ developerConnection = "${gitUrl}.git"
+ url = "$gitUrl"
+ }
+ }
+ }
+ }
+
+ repositories {
+
+ maven {
+ // 依赖发布地址
+ def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/"
+ def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/"
+ url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
+
+ // 配置账号密码
+ println "user=${ossrhUsername},key=${ossrhPassword}"
+ credentials {
+ username "${ossrhUsername}"
+ password "${ossrhPassword}"
+ }
+ }
+ }
+ }
+
+ signing {
+ sign publishing.publications.mavenAndroid
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/build.gradle b/sample/build.gradle
index 85a2529..00bc09a 100644
--- a/sample/build.gradle
+++ b/sample/build.gradle
@@ -10,7 +10,7 @@ android {
versionCode 1
versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
buildTypes {
release {
@@ -22,10 +22,11 @@ android {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
- androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
+ androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', {
exclude group: 'com.android.support', module: 'support-annotations'
})
- implementation 'com.android.support:appcompat-v7:27.1.1'
- testImplementation 'junit:junit:4.12'
- implementation project(':serialport')
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ testImplementation 'junit:junit:4.13'
+ //implementation project(':serialport')
+ implementation 'com.licheedev:android-serialport:2.1.5'
}
diff --git a/sample/src/androidTest/java/android/serialport/sample/ExampleInstrumentedTest.java b/sample/src/androidTest/java/android/serialport/sample/ExampleInstrumentedTest.java
index b65e8d8..a7501ea 100644
--- a/sample/src/androidTest/java/android/serialport/sample/ExampleInstrumentedTest.java
+++ b/sample/src/androidTest/java/android/serialport/sample/ExampleInstrumentedTest.java
@@ -1,8 +1,8 @@
package android.serialport.sample;
import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/serialport/.gitignore b/serialport/.gitignore
index a222170..968c49e 100644
--- a/serialport/.gitignore
+++ b/serialport/.gitignore
@@ -1,2 +1,3 @@
/build
.externalNativeBuild
+.cxx
diff --git a/serialport/CMakeLists.txt b/serialport/CMakeLists.txt
index f16cb32..80def00 100644
--- a/serialport/CMakeLists.txt
+++ b/serialport/CMakeLists.txt
@@ -2,7 +2,7 @@
# This ensures that a certain set of CMake features is available to
# your build.
-cmake_minimum_required(VERSION 3.4.1)
+cmake_minimum_required(VERSION 3.18.1)
# Specifies a library name, specifies whether the library is STATIC or
# SHARED, and provides relative paths to the source code. You can
@@ -35,4 +35,10 @@ target_link_libraries( # Specifies the target library.
# Links the target library to the log library
# included in the NDK.
- ${log-lib} )
\ No newline at end of file
+ ${log-lib} )
+
+target_link_options(
+ serial_port
+ PRIVATE
+ "-Wl,-z,max-page-size=16384"
+)
\ No newline at end of file
diff --git a/serialport/build.gradle b/serialport/build.gradle
index 7f171a1..b5a36b4 100644
--- a/serialport/build.gradle
+++ b/serialport/build.gradle
@@ -7,10 +7,10 @@ android {
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
- versionCode rootProject.ext.versionCode
+ versionCode 1
versionName rootProject.ext.versionName
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
buildTypes {
release {
@@ -21,6 +21,12 @@ android {
externalNativeBuild {
cmake {
path 'CMakeLists.txt'
+ version "3.18.1"
+ }
+ }
+ packagingOptions {
+ jniLibs {
+ useLegacyPackaging true
}
}
}
@@ -32,7 +38,10 @@ dependencies {
// })
// compile 'com.android.support:appcompat-v7:25.3.0'
// testCompile 'junit:junit:4.12'
+
+
+ api "androidx.annotation:annotation:1.1.0"
}
-apply from: '../jitpack.gradle'
+apply from: '../maven_publish.gradle'
diff --git a/serialport/src/main/AndroidManifest.xml b/serialport/src/main/AndroidManifest.xml
index 808f2ee..6c1ed51 100644
--- a/serialport/src/main/AndroidManifest.xml
+++ b/serialport/src/main/AndroidManifest.xml
@@ -1,10 +1,4 @@
-
-
-
-
-
-
+
+
diff --git a/serialport/src/main/java/android/serialport/SerialPort.java b/serialport/src/main/java/android/serialport/SerialPort.java
index 7633b3c..a07b705 100644
--- a/serialport/src/main/java/android/serialport/SerialPort.java
+++ b/serialport/src/main/java/android/serialport/SerialPort.java
@@ -17,6 +17,8 @@
package android.serialport;
import android.util.Log;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -32,13 +34,19 @@ public final class SerialPort {
public static final String DEFAULT_SU_PATH = "/system/bin/su";
private static String sSuPath = DEFAULT_SU_PATH;
+ private File device;
+ private int baudrate;
+ private int dataBits;
+ private int parity;
+ private int stopBits;
+ private int flags;
/**
* Set the su binary path, the default su binary path is {@link #DEFAULT_SU_PATH}
*
* @param suPath su binary path
*/
- public static void setSuPath(String suPath) {
+ public static void setSuPath(@Nullable String suPath) {
if (suPath == null) {
return;
}
@@ -50,6 +58,7 @@ public static void setSuPath(String suPath) {
*
* @return
*/
+ @NonNull
public static String getSuPath() {
return sSuPath;
}
@@ -66,15 +75,28 @@ public static String getSuPath() {
*
* @param device 串口设备文件
* @param baudrate 波特率
- * @param dataBits 数据位,默认8
- * @param parity 奇偶校验位,默认0(无校验)
- * @param stopBits 停止位,默认1
+ * @param dataBits 数据位;默认8,可选值为5~8
+ * @param parity 奇偶校验;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN)
+ * @param stopBits 停止位;默认1;1:1位停止位;2:2位停止位
* @param flags 默认0
* @throws SecurityException
* @throws IOException
*/
- private SerialPort(File device, int baudrate, int dataBits, int parity, int stopBits, int flags)
- throws SecurityException, IOException {
+ public SerialPort(
+ @NonNull File device, int baudrate, int dataBits, int parity, int stopBits,
+ int flags
+ ) throws SecurityException, IOException {
+
+ this.device = device;
+ this.baudrate = baudrate;
+ this.dataBits = dataBits;
+ this.parity = parity;
+ this.stopBits = stopBits;
+ this.flags = flags;
+
+ if (!device.exists()) {
+ throw new IOException("SerialPort(" + device.getAbsolutePath() + ") not exists");
+ }
/* Check access permission */
if (!device.canRead() || !device.canWrite()) {
@@ -96,27 +118,112 @@ private SerialPort(File device, int baudrate, int dataBits, int parity, int stop
mFd = open(device.getAbsolutePath(), baudrate, dataBits, parity, stopBits, flags);
if (mFd == null) {
Log.e(TAG, "native open returns null");
- throw new IOException();
+ throw new IOException("native open" +
+ "SerialPort(" + device.getAbsolutePath()
+ + ") returns null");
}
mFileInputStream = new FileInputStream(mFd);
mFileOutputStream = new FileOutputStream(mFd);
}
+ /**
+ * 串口,默认的8n1
+ *
+ * @param device 串口设备文件
+ * @param baudrate 波特率
+ * @throws SecurityException
+ * @throws IOException
+ */
+ public SerialPort(@NonNull File device, int baudrate) throws SecurityException, IOException {
+ this(device, baudrate, 8, 0, 1, 0);
+ }
+
+ /**
+ * 串口
+ *
+ * @param device 串口设备文件
+ * @param baudrate 波特率
+ * @param dataBits 数据位;默认8,可选值为5~8
+ * @param parity 奇偶校验;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN)
+ * @param stopBits 停止位;默认1;1:1位停止位;2:2位停止位
+ * @throws SecurityException
+ * @throws IOException
+ */
+ public SerialPort(@NonNull File device, int baudrate, int dataBits, int parity, int stopBits)
+ throws SecurityException, IOException {
+ this(device, baudrate, dataBits, parity, stopBits, 0);
+ }
+
// Getters and setters
+ @NonNull
public InputStream getInputStream() {
return mFileInputStream;
}
+ @NonNull
public OutputStream getOutputStream() {
return mFileOutputStream;
}
+ /** 串口设备文件 */
+ @NonNull
+ public File getDevice() {
+ return device;
+ }
+
+ /** 波特率 */
+ public int getBaudrate() {
+ return baudrate;
+ }
+
+ /** 数据位;默认8,可选值为5~8 */
+ public int getDataBits() {
+ return dataBits;
+ }
+
+ /** 奇偶校验;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN) */
+ public int getParity() {
+ return parity;
+ }
+
+ /** 停止位;默认1;1:1位停止位;2:2位停止位 */
+ public int getStopBits() {
+ return stopBits;
+ }
+
+ public int getFlags() {
+ return flags;
+ }
+
// JNI
- private native FileDescriptor open(String absolutePath, int baudrate, int dataBits, int parity,
- int stopBits, int flags);
+ private native FileDescriptor open(
+ String absolutePath, int baudrate, int dataBits, int parity,
+ int stopBits, int flags
+ );
public native void close();
+ /** 关闭流和串口,已经try-catch */
+ public void tryClose() {
+ try {
+ mFileInputStream.close();
+ } catch (IOException e) {
+ //e.printStackTrace();
+ }
+
+ try {
+ mFileOutputStream.close();
+ } catch (IOException e) {
+ //e.printStackTrace();
+ }
+
+ try {
+ close();
+ } catch (Exception e) {
+ //e.printStackTrace();
+ }
+ }
+
static {
System.loadLibrary("serial_port");
}