Golang中GOMOBILE在Android 19以上版本的权限问题

Golang中GOMOBILE在Android 19以上版本的权限问题 这个问题已经存在相当长一段时间了,并且在其他上下文中被多次提出,例如这里:

x/mobile: Calling net.InterfaceAddrs() fails on Android SDK 30

到目前为止还没有解决方案。我想知道,如果这个问题不能在不久的将来得到解决,因为它会妨碍在 Android 下正确使用 GOMOBILE 模块的网络功能。这是一个由 API 30 引入的权限问题,影响所有运行 GOMOBILE 且 Android 版本大于 10 的设备。

在我的案例中,这个问题在我使用基于 PION GO WebRtc 的 LiveKit GO SDK 时出现。

目前没有已知的解决办法。

I/GoLog: "msg"="could not create answer" "error"="failed to create network: route ip+net: netlinkrib: permission denied"
I/GoLog: "msg"="could not set remote description" "error"="failed to create network: route ip+net: netlinkrib: permission denied"
I/GoLog: "msg"="could not add ICE candidate" "error"="failed to create network: route ip+net: netlinkrib: permission denied"
I/GoLog: "msg"="could not add ICE candidate" "error"="failed to create network: route ip+net: netlinkrib: permission denied"

更多关于Golang中GOMOBILE在Android 19以上版本的权限问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

抱歉,标题有笔误。应该是 Android > 10。

更多关于Golang中GOMOBILE在Android 19以上版本的权限问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是一个在Android 10(API 29)及以上版本中确实存在的权限限制问题。从Android 10开始,应用对网络接口信息的访问受到了更严格的限制,导致net.InterfaceAddrs()等网络相关调用在非系统应用中会失败。

问题的核心是Android的权限模型变更。在API 29+中,普通应用无法直接访问/proc/net目录和网络路由表,而Go的net包在Android上正是通过这些系统文件来获取网络信息的。

目前可以通过以下两种方式解决:

1. 使用Android的Network API(推荐)

在Go代码中通过JNI调用Android的ConnectivityManager来获取网络信息:

// +build android

package main

/*
#include <jni.h>
#include <stdlib.h>
*/
import "C"
import (
    "net"
    "unsafe"
)

// 通过JNI获取网络接口信息
func getNetworkInterfaces() ([]net.IP, error) {
    // 获取Android上下文
    ctx := getAndroidContext()
    
    // 调用ConnectivityManager获取活动网络信息
    jniEnv := getJNIEnv()
    
    // 获取ConnectivityManager实例
    connectivityManager := getConnectivityManager(jniEnv, ctx)
    
    // 获取活动网络信息
    networkInfo := getActiveNetworkInfo(jniEnv, connectivityManager)
    
    // 解析IP地址
    return parseNetworkAddresses(jniEnv, networkInfo)
}

// 实际的JNI调用实现
func getActiveNetworkInfo(env *C.JNIEnv, cm C.jobject) C.jobject {
    // JNI调用ConnectivityManager.getActiveNetworkInfo()
    // 这里需要完整的JNI实现
    return nil
}

2. 修改Go标准库的net包实现

创建一个自定义的net包实现,避免使用受限的系统调用:

// custom_net_android.go
// +build android

package customnet

import (
    "errors"
    "net"
    "syscall"
)

// 重写InterfaceAddrs函数
func InterfaceAddrs() ([]net.Addr, error) {
    // 尝试使用Android的NetworkCapabilities API
    addrs, err := getAddressesViaAndroidAPI()
    if err == nil {
        return addrs, nil
    }
    
    // 回退到有限的信息获取
    return getLimitedAddresses()
}

func getAddressesViaAndroidAPI() ([]net.Addr, error) {
    // 实现通过JNI调用Android Network API的逻辑
    // 获取ConnectivityManager -> Network -> LinkProperties -> LinkAddresses
    return nil, errors.New("not implemented")
}

func getLimitedAddresses() ([]net.Addr, error) {
    // 返回基本的本地地址(如127.0.0.1)
    return []net.Addr{
        &net.IPNet{
            IP:   net.IPv4(127, 0, 0, 1),
            Mask: net.CIDRMask(8, 32),
        },
    }, nil
}

3. 对于WebRTC的具体解决方案

对于使用Pion WebRTC的情况,可以设置ICE服务器配置来避免网络探测:

package main

import (
    "github.com/pion/webrtc/v3"
)

func createWebRTCConfig() webrtc.Configuration {
    return webrtc.Configuration{
        ICEServers: []webrtc.ICEServer{
            {
                URLs: []string{"stun:stun.l.google.com:19302"},
            },
        },
        ICETransportPolicy: webrtc.ICETransportPolicyRelay, // 强制使用中继
    }
}

func main() {
    config := createWebRTCConfig()
    
    // 创建PeerConnection时使用配置
    peerConnection, err := webrtc.NewPeerConnection(config)
    if err != nil {
        // 处理错误
    }
    
    // 设置ICE候选收集策略
    peerConnection.SetICECandidateFilter(func(c webrtc.ICECandidate) bool {
        // 只允许中继类型的候选
        return c.Typ == webrtc.ICECandidateTypeRelay
    })
}

4. 在AndroidManifest.xml中添加权限

确保在Android清单文件中声明必要的权限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

<!-- 对于API 29+ -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" 
    android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" 
    android:maxSdkVersion="28" />

这个问题确实影响了Go在Android上的网络功能使用,目前最可行的方案是通过JNI桥接Android的原生网络API,或者调整应用逻辑以避免直接访问受限的网络接口信息。

回到顶部