diff --git a/Android/app/build.gradle.kts b/Android/app/build.gradle.kts index d67fce7..98cb2b9 100644 --- a/Android/app/build.gradle.kts +++ b/Android/app/build.gradle.kts @@ -11,14 +11,17 @@ android { applicationId = "com.krxkli.scut_router" minSdk = 24 targetSdk = 34 - versionCode = 1 - versionName = "1.0" + versionCode = 2 + versionName = "1.1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" // Golang 库为下列架构 ndk { abiFilters.add("arm64-v8a") + abiFilters.add("armeabi-v7a") + abiFilters.add("x86_64") +// abiFilters.add("x86") // 暂时不支持 } } diff --git a/Android/app/release/app-release.apk b/Android/app/release/app-release.apk index 42983c6..d3b54f6 100644 Binary files a/Android/app/release/app-release.apk and b/Android/app/release/app-release.apk differ diff --git a/Android/app/release/baselineProfiles/0/app-release.dm b/Android/app/release/baselineProfiles/0/app-release.dm index 7660101..005ed0d 100644 Binary files a/Android/app/release/baselineProfiles/0/app-release.dm and b/Android/app/release/baselineProfiles/0/app-release.dm differ diff --git a/Android/app/release/baselineProfiles/1/app-release.dm b/Android/app/release/baselineProfiles/1/app-release.dm index 529f2e0..496c1de 100644 Binary files a/Android/app/release/baselineProfiles/1/app-release.dm and b/Android/app/release/baselineProfiles/1/app-release.dm differ diff --git a/Android/app/release/output-metadata.json b/Android/app/release/output-metadata.json index f1c8431..9e6a44b 100644 --- a/Android/app/release/output-metadata.json +++ b/Android/app/release/output-metadata.json @@ -11,8 +11,8 @@ "type": "SINGLE", "filters": [], "attributes": [], - "versionCode": 1, - "versionName": "1.0", + "versionCode": 2, + "versionName": "1.1.0", "outputFile": "app-release.apk" } ], diff --git a/Android/app/src/main/AndroidManifest.xml b/Android/app/src/main/AndroidManifest.xml index 63bcb40..4f0c8d5 100644 --- a/Android/app/src/main/AndroidManifest.xml +++ b/Android/app/src/main/AndroidManifest.xml @@ -3,8 +3,12 @@ xmlns:tools="http://schemas.android.com/tools"> + + + + #include -#include "libSSHCommand.h" + +// 检测 Android 架构 +#if defined(__ANDROID__) +#if defined(__x86__) +#define ARCHITECTURE "x86" +#include "../jniLibs/x86/libSSHCommand.h" +#elif defined(__x86_64__) +#define ARCHITECTURE "x86_64" +#include "../jniLibs/x86_64/libSSHCommand.h" +#elif defined(__arm__) +#define ARCHITECTURE "ARM" +#include "../jniLibs/armeabi-v7a/libSSHCommand.h" +#elif defined(__aarch64__) +#define ARCHITECTURE "ARM64" +#include "../jniLibs/arm64-v8a/libSSHCommand.h" +#else +#define ARCHITECTURE "Unknown Architecture" +#endif +#else +#define ARCHITECTURE "Not an Android Platform" +#endif extern "C" JNIEXPORT void JNICALL @@ -68,12 +88,8 @@ Java_com_example_scut_1router_InternetActivity_setNetwork(JNIEnv *env, jobject t env->ReleaseStringUTFChars(gateway, gatewayStr); } -extern "C" -JNIEXPORT void JNICALL -Java_com_example_scut_1router_MainActivity_00024Companion_initLibSSHCommand(JNIEnv *env, - jobject thiz) { - Init(); -} + + extern "C" JNIEXPORT void JNICALL @@ -92,4 +108,16 @@ extern "C" JNIEXPORT void JNICALL Java_com_example_scut_1router_LoginActivity_cancelAutoLogin(JNIEnv *env, jobject thiz) { CancelAutoLogin(); +} +extern "C" +JNIEXPORT void JNICALL +Java_com_example_scut_1router_MainActivity_00024Companion_initLibSSHCommand(JNIEnv *env, + jobject thiz, + jstring download_path) { + + const char* download_pathStr = env->GetStringUTFChars(download_path, nullptr); + + Init((void *)download_pathStr); + + env->ReleaseStringUTFChars(download_path, download_pathStr); } \ No newline at end of file diff --git a/Android/app/src/main/java/com/example/scut_router/MainActivity.kt b/Android/app/src/main/java/com/example/scut_router/MainActivity.kt index 7a076b3..c633a1e 100644 --- a/Android/app/src/main/java/com/example/scut_router/MainActivity.kt +++ b/Android/app/src/main/java/com/example/scut_router/MainActivity.kt @@ -1,18 +1,29 @@ package com.example.scut_router +import android.Manifest import android.content.Intent +import android.content.pm.PackageManager import android.net.Uri +import android.os.Build import android.os.Bundle +import android.os.Environment +import android.provider.Settings +import android.widget.Toast import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat import com.example.scut_router.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding + val REQUEST_CODE: Int = 100 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + requestPermissions() // 请求文件管理权限 + binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) @@ -62,13 +73,77 @@ class MainActivity : AppCompatActivity() { private external fun destroyLibSSHCommand() companion object { - private external fun initLibSSHCommand() + private external fun initLibSSHCommand(downloadPath: String) // Used to load the 'scut_router' library on application startup. init { System.loadLibrary("scut_router") // 初始化 SSH 库 - initLibSSHCommand() + val downloadPath : String = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absolutePath + initLibSSHCommand(downloadPath) } } + + /** + * 请求文件读写权限 + */ + private fun requestPermissions() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + // Android 11 及更高版本,检查 MANAGE_EXTERNAL_STORAGE 权限 + if (Environment.isExternalStorageManager()) { + // 权限已被授予,可以进行文件操作 + Toast.makeText(this, "权限已成功获取,若首次授予请重启应用以正常运行", Toast.LENGTH_SHORT).show() + } else { + // 权限未被授予,提示用户去设置中开启 + val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION) + val uri = Uri.fromParts("package", packageName, null) + intent.data = uri + startActivity(intent) + } + } else { + // Android 10 及更低版本,检查 READ 和 WRITE 权限 + if (ContextCompat.checkSelfPermission( + this, + Manifest.permission.READ_EXTERNAL_STORAGE + ) != PackageManager.PERMISSION_GRANTED || + ContextCompat.checkSelfPermission( + this, + Manifest.permission.WRITE_EXTERNAL_STORAGE + ) != PackageManager.PERMISSION_GRANTED + ) { + ActivityCompat.requestPermissions( + this, arrayOf( + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE + ), REQUEST_CODE + ) + } + } + } + + override fun onRequestPermissionsResult(requestCode: Int, + permissions: Array, grantResults: IntArray) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + when (requestCode) { + REQUEST_CODE -> { + // If request is cancelled, the result arrays are empty. + if ((grantResults.isNotEmpty() && + grantResults[0] == PackageManager.PERMISSION_GRANTED)) { + // Permission is granted. Continue the action or workflow + // in your app. + Toast.makeText(this, "权限已成功获取,若首次授予请重启应用以正常运行", Toast.LENGTH_SHORT).show() + + } else { + Toast.makeText(this, "权限被拒绝,无法正常工作,请重启", Toast.LENGTH_SHORT).show() + } + return + } + + // Add other 'when' lines to check for other + // permissions this app might request. + else -> { + // Ignore all other requests. + } + } + } } \ No newline at end of file diff --git a/Android/app/src/main/jniLibs/arm64-v8a/libSSHCommand.h b/Android/app/src/main/jniLibs/arm64-v8a/libSSHCommand.h new file mode 100644 index 0000000..220833f --- /dev/null +++ b/Android/app/src/main/jniLibs/arm64-v8a/libSSHCommand.h @@ -0,0 +1,91 @@ +/* Code generated by cmd/cgo; DO NOT EDIT. */ + +/* package command-line-arguments */ + + +#line 1 "cgo-builtin-export-prolog" + +#include + +#ifndef GO_CGO_EXPORT_PROLOGUE_H +#define GO_CGO_EXPORT_PROLOGUE_H + +#ifndef GO_CGO_GOSTRING_TYPEDEF +typedef struct { const char *p; ptrdiff_t n; } _GoString_; +#endif + +#endif + +/* Start of preamble from import "C" comments. */ + + + + +/* End of preamble from import "C" comments. */ + + +/* Start of boilerplate cgo prologue. */ +#line 1 "cgo-gcc-export-header-prolog" + +#ifndef GO_CGO_PROLOGUE_H +#define GO_CGO_PROLOGUE_H + +typedef signed char GoInt8; +typedef unsigned char GoUint8; +typedef short GoInt16; +typedef unsigned short GoUint16; +typedef int GoInt32; +typedef unsigned int GoUint32; +typedef long long GoInt64; +typedef unsigned long long GoUint64; +typedef GoInt64 GoInt; +typedef GoUint64 GoUint; +typedef size_t GoUintptr; +typedef float GoFloat32; +typedef double GoFloat64; +#ifdef _MSC_VER +#include +typedef _Fcomplex GoComplex64; +typedef _Dcomplex GoComplex128; +#else +typedef float _Complex GoComplex64; +typedef double _Complex GoComplex128; +#endif + +/* + static assertion to make sure the file is being used on architecture + at least with matching size of GoInt. +*/ +typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1]; + +#ifndef GO_CGO_GOSTRING_TYPEDEF +typedef _GoString_ GoString; +#endif +typedef void *GoMap; +typedef void *GoChan; +typedef struct { void *t; void *v; } GoInterface; +typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; + +#endif + +/* End of boilerplate cgo prologue. */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void Init(void* downloadPath); +extern void Destroy(); +extern void Reboot(); +extern void WiredLogin(); +extern void WirelessLogin(); +extern void SyncTime(); +extern void AutoLogin(); +extern void CancelAutoLogin(); +extern void SetScutInfo(void* username, void* password); +extern void SetAcInfo(void* acIP, void* acName); +extern void SetNetwork(void* ip, void* dnsArr, void* netmask, void* gateway); + +#ifdef __cplusplus +} +#endif diff --git a/Android/app/src/main/jniLibs/arm64-v8a/libSSHCommand.so b/Android/app/src/main/jniLibs/arm64-v8a/libSSHCommand.so index ed428e4..9139c6f 100644 Binary files a/Android/app/src/main/jniLibs/arm64-v8a/libSSHCommand.so and b/Android/app/src/main/jniLibs/arm64-v8a/libSSHCommand.so differ diff --git a/Android/app/src/main/jniLibs/armeabi-v7a/libSSHCommand.h b/Android/app/src/main/jniLibs/armeabi-v7a/libSSHCommand.h new file mode 100644 index 0000000..48c855f --- /dev/null +++ b/Android/app/src/main/jniLibs/armeabi-v7a/libSSHCommand.h @@ -0,0 +1,91 @@ +/* Code generated by cmd/cgo; DO NOT EDIT. */ + +/* package command-line-arguments */ + + +#line 1 "cgo-builtin-export-prolog" + +#include + +#ifndef GO_CGO_EXPORT_PROLOGUE_H +#define GO_CGO_EXPORT_PROLOGUE_H + +#ifndef GO_CGO_GOSTRING_TYPEDEF +typedef struct { const char *p; ptrdiff_t n; } _GoString_; +#endif + +#endif + +/* Start of preamble from import "C" comments. */ + + + + +/* End of preamble from import "C" comments. */ + + +/* Start of boilerplate cgo prologue. */ +#line 1 "cgo-gcc-export-header-prolog" + +#ifndef GO_CGO_PROLOGUE_H +#define GO_CGO_PROLOGUE_H + +typedef signed char GoInt8; +typedef unsigned char GoUint8; +typedef short GoInt16; +typedef unsigned short GoUint16; +typedef int GoInt32; +typedef unsigned int GoUint32; +typedef long long GoInt64; +typedef unsigned long long GoUint64; +typedef GoInt32 GoInt; +typedef GoUint32 GoUint; +typedef size_t GoUintptr; +typedef float GoFloat32; +typedef double GoFloat64; +#ifdef _MSC_VER +#include +typedef _Fcomplex GoComplex64; +typedef _Dcomplex GoComplex128; +#else +typedef float _Complex GoComplex64; +typedef double _Complex GoComplex128; +#endif + +/* + static assertion to make sure the file is being used on architecture + at least with matching size of GoInt. +*/ +typedef char _check_for_32_bit_pointer_matching_GoInt[sizeof(void*)==32/8 ? 1:-1]; + +#ifndef GO_CGO_GOSTRING_TYPEDEF +typedef _GoString_ GoString; +#endif +typedef void *GoMap; +typedef void *GoChan; +typedef struct { void *t; void *v; } GoInterface; +typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; + +#endif + +/* End of boilerplate cgo prologue. */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void Init(void* downloadPath); +extern void Destroy(); +extern void Reboot(); +extern void WiredLogin(); +extern void WirelessLogin(); +extern void SyncTime(); +extern void AutoLogin(); +extern void CancelAutoLogin(); +extern void SetScutInfo(void* username, void* password); +extern void SetAcInfo(void* acIP, void* acName); +extern void SetNetwork(void* ip, void* dnsArr, void* netmask, void* gateway); + +#ifdef __cplusplus +} +#endif diff --git a/Android/app/src/main/jniLibs/armeabi-v7a/libSSHCommand.so b/Android/app/src/main/jniLibs/armeabi-v7a/libSSHCommand.so new file mode 100644 index 0000000..96bf492 Binary files /dev/null and b/Android/app/src/main/jniLibs/armeabi-v7a/libSSHCommand.so differ diff --git a/Android/app/src/main/jniLibs/x86_64/libSSHCommand.h b/Android/app/src/main/jniLibs/x86_64/libSSHCommand.h new file mode 100644 index 0000000..220833f --- /dev/null +++ b/Android/app/src/main/jniLibs/x86_64/libSSHCommand.h @@ -0,0 +1,91 @@ +/* Code generated by cmd/cgo; DO NOT EDIT. */ + +/* package command-line-arguments */ + + +#line 1 "cgo-builtin-export-prolog" + +#include + +#ifndef GO_CGO_EXPORT_PROLOGUE_H +#define GO_CGO_EXPORT_PROLOGUE_H + +#ifndef GO_CGO_GOSTRING_TYPEDEF +typedef struct { const char *p; ptrdiff_t n; } _GoString_; +#endif + +#endif + +/* Start of preamble from import "C" comments. */ + + + + +/* End of preamble from import "C" comments. */ + + +/* Start of boilerplate cgo prologue. */ +#line 1 "cgo-gcc-export-header-prolog" + +#ifndef GO_CGO_PROLOGUE_H +#define GO_CGO_PROLOGUE_H + +typedef signed char GoInt8; +typedef unsigned char GoUint8; +typedef short GoInt16; +typedef unsigned short GoUint16; +typedef int GoInt32; +typedef unsigned int GoUint32; +typedef long long GoInt64; +typedef unsigned long long GoUint64; +typedef GoInt64 GoInt; +typedef GoUint64 GoUint; +typedef size_t GoUintptr; +typedef float GoFloat32; +typedef double GoFloat64; +#ifdef _MSC_VER +#include +typedef _Fcomplex GoComplex64; +typedef _Dcomplex GoComplex128; +#else +typedef float _Complex GoComplex64; +typedef double _Complex GoComplex128; +#endif + +/* + static assertion to make sure the file is being used on architecture + at least with matching size of GoInt. +*/ +typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1]; + +#ifndef GO_CGO_GOSTRING_TYPEDEF +typedef _GoString_ GoString; +#endif +typedef void *GoMap; +typedef void *GoChan; +typedef struct { void *t; void *v; } GoInterface; +typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; + +#endif + +/* End of boilerplate cgo prologue. */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void Init(void* downloadPath); +extern void Destroy(); +extern void Reboot(); +extern void WiredLogin(); +extern void WirelessLogin(); +extern void SyncTime(); +extern void AutoLogin(); +extern void CancelAutoLogin(); +extern void SetScutInfo(void* username, void* password); +extern void SetAcInfo(void* acIP, void* acName); +extern void SetNetwork(void* ip, void* dnsArr, void* netmask, void* gateway); + +#ifdef __cplusplus +} +#endif diff --git a/Android/app/src/main/jniLibs/x86_64/libSSHCommand.so b/Android/app/src/main/jniLibs/x86_64/libSSHCommand.so new file mode 100644 index 0000000..a7d8a87 Binary files /dev/null and b/Android/app/src/main/jniLibs/x86_64/libSSHCommand.so differ diff --git a/Compatibility/CompatibleRunSSH.go b/Compatibility/CompatibleRunSSH.go index 48d1c8f..0152f5a 100644 --- a/Compatibility/CompatibleRunSSH.go +++ b/Compatibility/CompatibleRunSSH.go @@ -31,9 +31,11 @@ func fileExists(filename string) bool { } //export Init -func Init() { +func Init(downloadPath unsafe.Pointer) { if CompatibleSSHObj == nil { - outPath := "/sdcard/Download/Scut-Router" + downloadPathStr := C.GoString((*C.char)(downloadPath)) + outPath := downloadPathStr + "/Scut-Router" + //"/sdcard/Download/Scut-Router" if !fileExists(outPath) { err := os.MkdirAll(outPath, 0777) if err != nil { diff --git a/Compatibility/backup_GoEnv.txt b/Compatibility/backup_GoEnv.txt index 17ffab3..73a8e50 100644 --- a/Compatibility/backup_GoEnv.txt +++ b/Compatibility/backup_GoEnv.txt @@ -1,5 +1,5 @@ set GO111MODULE= -set GOARCH=arm64 +set GOARCH=386 set GOBIN= set GOCACHE=C:\Users\krxkli\AppData\Local\go-build set GOENV=C:\Users\krxkli\AppData\Roaming\go\env @@ -24,9 +24,10 @@ set GOTOOLDIR=C:\Program Files\Go\pkg\tool\windows_amd64 set GOVCS= set GOVERSION=go1.22.5 set GCCGO=gccgo +set GO386=sse2 set AR=ar -set CC=C:/Users/krxkli/AppData/Local/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/windows-x86_64/bin/aarch64-linux-android34-clang -set CXX=C:/Users/krxkli/AppData/Local/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/windows-x86_64/bin/aarch64-linux-android34-clang++ +set CC=C:/Users/krxkli/AppData/Local/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/windows-x86_64/bin/i686-linux-android34-clang +set CXX=C:/Users/krxkli/AppData/Local/Android/Sdk/ndk/27.0.12077973/toolchains/llvm/prebuilt/windows-x86_64/bin/i686-linux-android34-clang++ set CGO_ENABLED=1 set GOMOD=D:\krxkli\Projects\Scut-Router\go.mod set GOWORK= @@ -36,4 +37,4 @@ set CGO_CXXFLAGS=-O2 -g set CGO_FFLAGS=-O2 -g set CGO_LDFLAGS=-O2 -g set PKG_CONFIG=pkg-config -set GOGCCFLAGS=-fPIC -pthread -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=C:\Users\krxkli\AppData\Local\Temp\go-build626219188=/tmp/go-build -gno-record-gcc-switches +set GOGCCFLAGS=-fPIC -m32 -pthread -fno-caret-diagnostics -Qunused-arguments -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=C:\Users\krxkli\AppData\Local\Temp\go-build2780943356=/tmp/go-build -gno-record-gcc-switches diff --git a/Compatibility/build_android.sh b/Compatibility/build_android.sh index 3621881..56496bf 100644 --- a/Compatibility/build_android.sh +++ b/Compatibility/build_android.sh @@ -6,21 +6,50 @@ go env > backup_GoEnv.txt SDK_HOME=${HOME}/AppData/Local/Android/Sdk go env -w CGO_ENABLED=1 -go env -w GOARCH=arm64 -go env -w GOOS=android +go env -w GOOS=android # 指定安卓系统 + +# 编译并拷贝 so 到JniLibs 用于一并打包 +function build_and_copy_to_jnilibs { + go build -o ./out/libSSHCommand.so -buildmode=c-shared CompatibleMain.go CompatibleRunSSH.go + dest_folder="../Android/app/src/main/jniLibs/$1/" + if [ -d "$folder" ]; then + rm -rf ${dest_folder} + fi + + mkdir -p ${dest_folder} + cp ./out/libSSHCommand.h ${dest_folder}/libSSHCommand.h + cp ./out/libSSHCommand.so ${dest_folder}/libSSHCommand.so +} + -# 下列请替换此为NDK 的 clang 路径 +# 配置交叉编译环境:下列请替换此为NDK 的 clang 路径 PREFIX="${SDK_HOME}/ndk/27.0.12077973/toolchains/llvm/prebuilt/windows-x86_64/bin/" + + +# arm 64 +go env -w GOARCH=arm64 go env -w CC="${PREFIX}/aarch64-linux-android34-clang" go env -w CXX="${PREFIX}/aarch64-linux-android34-clang++" -go build -o ./out/libSSHCommand.so -buildmode=c-shared CompatibleMain.go CompatibleRunSSH.go +build_and_copy_to_jnilibs "arm64-v8a" + +# arm +go env -w GOARCH=arm +go env -w CC="${PREFIX}/armv7a-linux-androideabi34-clang" +go env -w CXX="${PREFIX}/armv7a-linux-androideabi34-clang++" + +build_and_copy_to_jnilibs "armeabi-v7a" -# 拷贝 so 到JniLibs 用于一并打包 -dest_folder="../Android/app/src/main/jniLibs/arm64-v8a/" -if [ -d "$folder" ]; then - rm -rf ${dest_folder} -fi +# x86_64 +go env -w GOARCH=amd64 +go env -w CC="${PREFIX}/x86_64-linux-android34-clang" +go env -w CXX="${PREFIX}/x86_64-linux-android34-clang++" -mkdir -p ${dest_folder} -cp ./out/libSSHCommand.so ${dest_folder}/libSSHCommand.so \ No newline at end of file +build_and_copy_to_jnilibs "x86_64" + +# x86 (暂时不支持) +#go env -w GOARCH=386 +#go env -w CC="${PREFIX}/i686-linux-android34-clang" +#go env -w CXX="${PREFIX}/i686-linux-android34-clang++" +# +#build_and_copy_to_jnilibs "x86" \ No newline at end of file