You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 11:58:12