如何在Android的gomobile中通过Go代码获取PackageName与应用签名?
如何在gomobile的Go代码中获取Android应用的包名与签名
1. 依赖准备
确保你的Go项目已引入gomobile相关依赖:
go get golang.org/x/mobile/bind go get golang.org/x/mobile/android
2. 获取应用包名(PackageName)
通过调用Android系统的Context.getPackageName()方法实现,gomobile已封装JNI调用逻辑,直接使用java.Call即可完成跨语言调用:
package yourlib import ( "fmt" "golang.org/x/mobile/android" "golang.org/x/mobile/bind/java" ) // GetPackageName 返回当前应用的包名 func GetPackageName() (string, error) { // 获取应用全局Context实例 ctx, err := android.AppContext() if err != nil { return "", fmt.Errorf("获取应用Context失败: %v", err) } // 调用Context的getPackageName方法 pkgNameObj, err := java.Call(ctx, "getPackageName") if err != nil { return "", fmt.Errorf("调用getPackageName失败: %v", err) } // 将Java返回值转为Go字符串类型 pkgName, ok := pkgNameObj.(string) if !ok { return "", fmt.Errorf("包名类型转换失败") } return pkgName, nil }
3. 获取应用签名信息
需要调用PackageManager的API,同时适配Android不同版本的签名获取逻辑(API28+推荐使用GET_SIGNING_CERTIFICATES,低版本使用GET_SIGNATURES):
package yourlib import ( "crypto/sha1" "fmt" "golang.org/x/mobile/android" "golang.org/x/mobile/bind/java" ) // GetAppSignatureSHA1 返回应用签名的SHA-1字符串(冒号分隔格式) func GetAppSignatureSHA1() (string, error) { ctx, err := android.AppContext() if err != nil { return "", err } // 获取PackageManager实例 pmObj, err := java.Call(ctx, "getPackageManager") if err != nil { return "", fmt.Errorf("获取PackageManager失败: %v", err) } pkgName, err := GetPackageName() if err != nil { return "", err } // 根据Android SDK版本选择对应的查询Flag sdkInt, err := android.SDKInt() if err != nil { return "", err } var flag int32 if sdkInt >= 28 { flag = 64 // GET_SIGNING_CERTIFICATES = 0x40 } else { flag = 65536 // GET_SIGNATURES = 0x10000 } // 获取PackageInfo对象 pkgInfoObj, err := java.Call(pmObj, "getPackageInfo", pkgName, flag) if err != nil { return "", fmt.Errorf("获取PackageInfo失败: %v", err) } // 适配新旧API获取签名对象 var signatureObj interface{} signatureObj, err = java.Get(pkgInfoObj, "signingInfo") if err != nil { // 低版本无signingInfo字段,直接读取signatures数组 signaturesArr, err := java.Get(pkgInfoObj, "signatures") if err != nil { return "", fmt.Errorf("获取签名数组失败: %v", err) } // 取第一个签名(普通应用通常只有一个签名) signatureObj, err = java.Call(signaturesArr, "get", 0) if err != nil { return "", fmt.Errorf("获取第一个签名失败: %v", err) } } else { // API28+通过signingInfo获取签名 apkSignaturesObj, err := java.Call(signatureObj, "getApkContentsSigners") if err != nil { return "", fmt.Errorf("获取APK签名者失败: %v", err) } signatureObj, err = java.Call(apkSignaturesObj, "get", 0) if err != nil { return "", fmt.Errorf("获取第一个签名者失败: %v", err) } } // 将签名转为字节数组 sigBytesObj, err := java.Call(signatureObj, "toByteArray") if err != nil { return "", fmt.Errorf("签名转字节数组失败: %v", err) } sigBytes, ok := sigBytesObj.([]byte) if !ok { return "", fmt.Errorf("签名字节数组类型转换失败") } // 计算SHA-1并格式化为冒号分隔的字符串 hash := sha1.Sum(sigBytes) var formattedSHA1 string for i, b := range hash { if i > 0 { formattedSHA1 += ":" } formattedSHA1 += fmt.Sprintf("%02x", b) } return formattedSHA1, nil }
4. gomobile中的JNICall说明
上述代码中用到的java.Call、java.Get就是gomobile封装好的JNICall工具,无需手动编写C层JNI代码:
java.Call(obj, methodName, args...):调用Java对象的方法,返回值会自动映射为对应的Go类型java.Get(obj, fieldName):读取Java对象的字段值android.AppContext():获取Android应用的全局Context,是调用绝大多数系统API的入口
5. 发送信息到服务器
使用Go标准库net/http发送POST请求即可,示例如下:
package yourlib import ( "bytes" "encoding/json" "fmt" "net/http" ) type appInfoPayload struct { PackageName string `json:"package_name"` Signature string `json:"signature"` } func SendAppInfo(serverURL string) error { pkgName, err := GetPackageName() if err != nil { return err } signature, err := GetAppSignatureSHA1() if err != nil { return err } payload := appInfoPayload{ PackageName: pkgName, Signature: signature, } jsonData, err := json.Marshal(payload) if err != nil { return fmt.Errorf("序列化请求数据失败: %v", err) } _, err = http.Post(serverURL, "application/json", bytes.NewBuffer(jsonData)) return err }
内容的提问来源于stack exchange,提问作者user19659782
相关产品推荐
相关产品推荐

