Skip to content

Commit 7efee8a

Browse files
committed
fix:增加查找层数
1 parent e812b05 commit 7efee8a

File tree

2 files changed

+142
-62
lines changed

2 files changed

+142
-62
lines changed

build.sh

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,50 @@ build_linux() {
212212
fi
213213
}
214214

215+
# 准备 Android 的 jniLibs
216+
prepare_android_jnilibs() {
217+
echo "=========================================="
218+
echo " 准备 Android JNI 库"
219+
echo "=========================================="
220+
221+
# 下载 ARM64 版本的 ECS 二进制
222+
echo "下载 ARM64 ECS 二进制..."
223+
download_ecs_binary "linux" "arm64"
224+
225+
# 下载 x86_64 版本的 ECS 二进制
226+
echo "下载 x86_64 ECS 二进制..."
227+
download_ecs_binary "linux" "amd64"
228+
229+
# 创建 jniLibs 目录结构
230+
mkdir -p jniLibs/arm64-v8a
231+
mkdir -p jniLibs/x86_64
232+
233+
# 复制二进制文件并重命名为 .so 库格式
234+
if [ -f "embedding/binaries/goecs-linux-arm64" ]; then
235+
cp "embedding/binaries/goecs-linux-arm64" "jniLibs/arm64-v8a/libgoecs.so"
236+
chmod 755 "jniLibs/arm64-v8a/libgoecs.so"
237+
echo "✓ ARM64 库已准备: jniLibs/arm64-v8a/libgoecs.so"
238+
echo " 文件大小: $(du -h jniLibs/arm64-v8a/libgoecs.so | cut -f1)"
239+
else
240+
echo "✗ 错误: 未找到 ARM64 ECS 二进制文件"
241+
exit 1
242+
fi
243+
244+
if [ -f "embedding/binaries/goecs-linux-amd64" ]; then
245+
cp "embedding/binaries/goecs-linux-amd64" "jniLibs/x86_64/libgoecs.so"
246+
chmod 755 "jniLibs/x86_64/libgoecs.so"
247+
echo "✓ x86_64 库已准备: jniLibs/x86_64/libgoecs.so"
248+
echo " 文件大小: $(du -h jniLibs/x86_64/libgoecs.so | cut -f1)"
249+
else
250+
echo "✗ 错误: 未找到 x86_64 ECS 二进制文件"
251+
exit 1
252+
fi
253+
254+
echo ""
255+
echo "JNI 库准备完成!"
256+
echo ""
257+
}
258+
215259
# Android 构建
216260
build_android() {
217261
VERSION=$(get_version)
@@ -227,31 +271,20 @@ build_android() {
227271

228272
mkdir -p .build
229273

230-
echo ""
231-
echo "构建 Android ARM64 版本..."
232-
download_ecs_binary "linux" "arm64"
233-
234-
fyne package -os android -appID com.oneclickvirt.goecs -appVersion "$VERSION"
235-
236-
if [ -f *.apk ]; then
237-
mv *.apk .build/goecs-android-arm64-${VERSION}.apk
238-
echo "Android ARM64 APK 构建成功"
239-
else
240-
echo "Android ARM64 APK 构建失败"
241-
exit 1
242-
fi
274+
# 准备 JNI 库
275+
prepare_android_jnilibs
243276

244277
echo ""
245-
echo "构建 Android x86_64 版本..."
246-
download_ecs_binary "linux" "amd64"
278+
echo "构建 Android APK..."
247279

248-
fyne package -os android/amd64 -appID com.oneclickvirt.goecs -appVersion "$VERSION"
280+
# 构建包含所有架构的 APK
281+
fyne package -os android -appID com.oneclickvirt.goecs -appVersion "$VERSION"
249282

250283
if [ -f *.apk ]; then
251-
mv *.apk .build/goecs-android-x86_64-${VERSION}.apk
252-
echo "Android x86_64 APK 构建成功"
284+
mv *.apk .build/goecs-android-${VERSION}.apk
285+
echo "Android APK 构建成功"
253286
else
254-
echo "Android x86_64 APK 构建失败"
287+
echo "Android APK 构建失败"
255288
exit 1
256289
fi
257290

embedding/embed_android.go

Lines changed: 90 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -13,37 +13,41 @@ import (
1313
// findNativeLibraryDir 查找应用的 native library 目录
1414
// 这个目录是系统自动管理的,包含从 APK 中提取的 .so 文件
1515
func findNativeLibraryDir() (string, error) {
16-
// 方法 1: 通过可执行文件路径推断
16+
// 方法 1: 通过环境变量获取(Fyne 可能会设置)
17+
if libDir := os.Getenv("ANDROID_LIB_DIR"); libDir != "" {
18+
if info, err := os.Stat(libDir); err == nil && info.IsDir() {
19+
return libDir, nil
20+
}
21+
}
22+
23+
// 方法 2: 通过可执行文件路径推断
1724
execPath, err := os.Executable()
1825
if err == nil {
1926
// 可执行文件通常在 /data/app/<package>-<hash>/base.apk 或 /data/app/<package>-<hash>/oat/arm64/base.odex
2027
// native library 通常在 /data/app/<package>-<hash>/lib/arm64/
2128

2229
// 尝试找到应用根目录
2330
dir := execPath
24-
for i := 0; i < 5; i++ { // 最多向上查找5层
31+
for i := 0; i < 10; i++ { // 最多向上查找10层
2532
dir = filepath.Dir(dir)
33+
if dir == "/" || dir == "." {
34+
break
35+
}
36+
2637
libDir := filepath.Join(dir, "lib")
2738

2839
// 检查 lib 目录
2940
if info, err := os.Stat(libDir); err == nil && info.IsDir() {
30-
// 检查是否包含架构子目录
41+
// 检查是否包含架构子目录或 .so 文件
3142
entries, err := os.ReadDir(libDir)
3243
if err == nil && len(entries) > 0 {
33-
// 如果 lib 目录有子目录(架构名),返回 lib 目录
34-
for _, entry := range entries {
35-
if entry.IsDir() {
36-
return libDir, nil
37-
}
38-
}
39-
// 如果 lib 目录直接包含 .so 文件,也返回
4044
return libDir, nil
4145
}
4246
}
4347
}
4448
}
4549

46-
// 方法 2: 尝试标准的 Android native library 路径
50+
// 方法 3: 尝试标准的 Android native library 路径
4751
possibleBasePaths := []string{
4852
"/data/data/com.oneclickvirt.goecs/lib",
4953
"/data/app/com.oneclickvirt.goecs/lib",
@@ -69,7 +73,7 @@ func findNativeLibraryDir() (string, error) {
6973
}
7074
}
7175

72-
// 方法 3: 搜索 /data/app 目录
76+
// 方法 4: 搜索 /data/app 目录
7377
dataAppDir := "/data/app"
7478
if entries, err := os.ReadDir(dataAppDir); err == nil {
7579
for _, entry := range entries {
@@ -82,39 +86,60 @@ func findNativeLibraryDir() (string, error) {
8286
}
8387
}
8488

85-
return "", fmt.Errorf("无法找到 native library 目录")
86-
}
87-
88-
// getLibraryName 获取当前架构对应的库名称
89-
func getLibraryName() string {
90-
switch runtime.GOARCH {
91-
case "arm64":
92-
return "libgoecs_arm64.so"
93-
case "amd64":
94-
return "libgoecs_amd64.so"
95-
case "arm":
96-
return "libgoecs_arm.so"
97-
case "386":
98-
return "libgoecs_386.so"
99-
default:
100-
return "libgoecs.so"
89+
// 方法 5: 尝试通过 /proc/self/maps 查找已加载的共享库路径
90+
if mapsData, err := os.ReadFile("/proc/self/maps"); err == nil {
91+
lines := strings.Split(string(mapsData), "\n")
92+
for _, line := range lines {
93+
// 查找包含 .so 的行
94+
if strings.Contains(line, ".so") && strings.Contains(line, "/data/") {
95+
// 提取路径部分
96+
parts := strings.Fields(line)
97+
if len(parts) >= 6 {
98+
soPath := parts[5]
99+
// 获取库目录
100+
libDir := filepath.Dir(soPath)
101+
// 向上查找到 lib 目录
102+
for i := 0; i < 3; i++ {
103+
if filepath.Base(libDir) == "lib" {
104+
return libDir, nil
105+
}
106+
libDir = filepath.Dir(libDir)
107+
}
108+
}
109+
}
110+
}
101111
}
112+
113+
return "", fmt.Errorf("无法找到 native library 目录")
102114
}
103115

104116
// ExtractECSBinary 获取 ECS 二进制文件路径
105117
// 在 Android 上,我们不需要"提取",而是直接使用系统已安装的 native library
106118
func ExtractECSBinary() (string, error) {
107119
// 获取 native library 目录
108120
libDir, err := findNativeLibraryDir()
121+
debugInfo := fmt.Sprintf("架构: %s/%s\n", runtime.GOOS, runtime.GOARCH)
122+
109123
if err != nil {
110-
return "", fmt.Errorf("获取 native library 目录失败: %v", err)
124+
debugInfo += fmt.Sprintf("查找 lib 目录失败: %v\n", err)
125+
} else {
126+
debugInfo += fmt.Sprintf("找到 lib 目录: %s\n", libDir)
127+
128+
// 列出 lib 目录内容
129+
if entries, err := os.ReadDir(libDir); err == nil {
130+
debugInfo += fmt.Sprintf("lib 目录内容 (%d 项):\n", len(entries))
131+
for _, entry := range entries {
132+
entryType := "文件"
133+
if entry.IsDir() {
134+
entryType = "目录"
135+
}
136+
debugInfo += fmt.Sprintf(" - %s (%s)\n", entry.Name(), entryType)
137+
}
138+
}
111139
}
112140

113-
// 尝试的文件名列表(按优先级)
114-
possibleNames := []string{
115-
"libgoecs.so", // 通用名称
116-
getLibraryName(), // 带架构后缀的名称
117-
}
141+
// 库名称固定为 libgoecs.so
142+
libraryName := "libgoecs.so"
118143

119144
// 尝试的子目录(Android ABI 名称)
120145
abiDirs := []string{
@@ -135,14 +160,15 @@ func ExtractECSBinary() (string, error) {
135160

136161
// 尝试所有可能的路径组合
137162
var checkedPaths []string
138-
for _, abiDir := range abiDirs {
139-
baseDir := libDir
140-
if abiDir != "" {
141-
baseDir = filepath.Join(libDir, abiDir)
142-
}
143163

144-
for _, name := range possibleNames {
145-
ecsPath := filepath.Join(baseDir, name)
164+
if err == nil {
165+
for _, abiDir := range abiDirs {
166+
baseDir := libDir
167+
if abiDir != "" {
168+
baseDir = filepath.Join(libDir, abiDir)
169+
}
170+
171+
ecsPath := filepath.Join(baseDir, libraryName)
146172
checkedPaths = append(checkedPaths, ecsPath)
147173

148174
if info, err := os.Stat(ecsPath); err == nil && !info.IsDir() {
@@ -155,10 +181,31 @@ func ExtractECSBinary() (string, error) {
155181
}
156182
}
157183

184+
// 如果上述方法都失败,尝试在常见位置查找
185+
// 注意:不再查找 /system/lib,因为那是系统库位置
186+
fallbackPaths := []string{
187+
"/data/local/tmp/libgoecs.so", // 临时目录(需要 root)
188+
}
189+
190+
for _, path := range fallbackPaths {
191+
checkedPaths = append(checkedPaths, path)
192+
if info, err := os.Stat(path); err == nil && !info.IsDir() {
193+
return path, nil
194+
}
195+
}
196+
158197
// 未找到文件,返回详细错误信息
159-
return "", fmt.Errorf("找不到 ECS 二进制文件\n已检查的路径:\n %s\n\n请确保:\n1. ECS 二进制文件已编译为 Android 版本\n2. 文件已放置在 jniLibs/%s/libgoecs.so\n3. APK 已重新打包",
198+
recommendedABI := "arm64-v8a"
199+
if runtime.GOARCH == "amd64" || runtime.GOARCH == "386" {
200+
recommendedABI = "x86_64"
201+
}
202+
203+
return "", fmt.Errorf("找不到 ECS 二进制文件\n\n调试信息:\n%s\n已检查的路径:\n %s\n\n请确保:\n1. ECS 二进制文件已编译为 Android 版本(Linux/%s)\n2. 文件已放置在 jniLibs/%s/libgoecs.so\n3. APK 已重新打包\n4. 当前架构: %s",
204+
debugInfo,
160205
strings.Join(checkedPaths, "\n "),
161-
abiDirs[1]) // 显示推荐的 ABI 目录
206+
runtime.GOARCH,
207+
recommendedABI,
208+
runtime.GOARCH)
162209
}
163210

164211
// CleanupECSBinary 清理函数

0 commit comments

Comments
 (0)