You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Unity中结合Google Play Services的NearbyConnections实现玩家间数据传输?

如何在Unity中结合Google Play Services的Nearby Connections实现玩家间数据传输?

我太懂你这种文档稀碎、插件还跟不上版本的痛苦了!之前做校园项目做类似Streetpass的功能时,我也在这上面摸爬滚打了好一阵,刚好把踩过的坑和可行的步骤整理给你,完全适配你要的近距离玩家数据传输需求~

一、前期准备:把Google Play Nearby Connections接入Unity

别去碰那些第三方旧插件了,直接用官方的Play Services包才是最稳的:

  • 打开Unity的Package Manager,搜索并安装Google Play Services Nearby Connections包(要是搜不到,先确认Unity版本在2020及以上,手动导入官方aar包也可以,但Package Manager更省心)
  • Project Settings > Android > Publishing Settings,勾选「Custom Main Manifest」,然后在自动生成的AndroidManifest.xml里添加Nearby必需的权限:
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.INTERNET" />
    
  • 去Google Cloud Console给你的应用配置Nearby Connections的API密钥,把对应的OAuth Client ID填到Unity的Google Play Services设置里——这步绝对不能忘!我当时就是漏了这个,两台手机死活搜不到对方。

二、核心功能实现:从发现到传数据

我把整个流程拆成了几个关键模块,你可以直接套进你的游戏逻辑里:

1. 初始化Nearby Connections

先整个单例类管理所有Nearby操作,避免重复初始化:

using GooglePlayGames.Nearby;
using GooglePlayGames;
using UnityEngine;

public class NearbyStreetpassManager : MonoBehaviour
{
    public static NearbyStreetpassManager Instance;
    private const string SERVICE_ID = "com.yourgame.streetpass.service"; // 用你的应用包名当唯一标识,两台设备必须一致!
    private string myPlayerTag;

    void Awake()
    {
        if (Instance == null) Instance = this;
        else Destroy(gameObject);
        DontDestroyOnLoad(gameObject);

        // 激活Play Games平台
        PlayGamesPlatform.Activate();
        myPlayerTag = PlayGamesPlatform.Instance.GetUserDisplayName(); // 用玩家的Google Play昵称当身份标识
    }
}

划重点:SERVICE_ID是设备匹配的核心,两台设备必须用完全相同的字符串,不然互相搜不到!我当时随便写了个名字,结果卡了一上午才发现问题。

2. 广播/发现设备(Streetpass核心:互相找到对方)

要做类似Streetpass的自动感应,要么让设备同时广播自己并搜索周边,要么做个简单UI让玩家选择「等待连接」或「搜索玩家」:

// 开始广播自己,让周边设备能搜到
public void StartBroadcasting()
{
    Nearby.Connections.StartAdvertising(
        myPlayerTag,
        SERVICE_ID,
        OnConnectionInvited,
        new AdvertisingOptions(Strategy.P2P_STAR), // 小范围设备用P2P_STAR模式最稳
        () => Debug.Log("已开始广播自己"),
        (error) => Debug.LogError($"广播失败:{error}")
    );
}

// 开始搜索周边的广播设备
public void StartDiscoveringPlayers()
{
    Nearby.Connections.StartDiscovery(
        SERVICE_ID,
        OnFoundNearbyPlayer,
        () => Debug.Log("已开始搜索周边玩家"),
        (error) => Debug.LogError($"搜索失败:{error}")
    );
}

// 搜到周边玩家时的回调
private void OnFoundNearbyPlayer(EndpointDetails endpointInfo)
{
    Debug.Log($"发现玩家:{endpointInfo.EndpointName},设备ID:{endpointInfo.EndpointId}");
    // 这里可以弹个UI让玩家选择是否发起连接
    Nearby.Connections.SendConnectionRequest(
        myPlayerTag,
        endpointInfo.EndpointId,
        OnConnectionSuccess,
        (error) => Debug.LogError($"请求连接失败:{error}")
    );
}

坑预警:Android 12及以上必须动态申请位置权限!一定要在游戏启动时用Permission.RequestUserPermission()弹权限请求,不然Nearby根本搜不到设备——我当时在测试机上卡到怀疑人生,最后才发现是权限没开。

3. 处理连接请求(建立双向连接)

收到别人的连接邀请,或者自己的请求被接受后,要确认连接:

// 收到其他玩家的连接邀请时
private void OnConnectionInvited(string endpointId, string playerName, byte[] payload)
{
    // 弹UI让玩家选择是否接受连接
    Nearby.Connections.AcceptConnection(
        endpointId,
        OnReceivedPlayerData, // 接收玩家数据的回调
        OnPayloadTransferUpdate,
        OnConnectionSuccess,
        (error) => Debug.LogError($"拒绝连接:{error}")
    );
}

// 连接成功的回调
private void OnConnectionSuccess(string endpointId, string playerName)
{
    Debug.Log($"已和玩家「{playerName}」建立连接!");
    // 这里触发你的游戏逻辑,比如显示「你遇到了玩家XXX」
}

4. 传输游戏数据(Streetpass核心:传玩家信息)

连接建立后,把你的游戏数据序列化成字节数组就能传输了,比如玩家ID、角色等级、自定义成就这些:

// 发送玩家数据给对方
public void SendStreetpassData(string endpointId, PlayerGameData myData)
{
    // 用JsonUtility序列化数据,简单够用
    byte[] dataBytes = System.Text.Encoding.UTF8.GetBytes(JsonUtility.ToJson(myData));
    Nearby.Connections.SendPayload(
        endpointId,
        Payload.FromBytes(dataBytes)
    );
}

// 收到对方数据的回调
private void OnReceivedPlayerData(string endpointId, Payload payload)
{
    if (payload.Type == Payload.Type.BYTES)
    {
        string dataStr = System.Text.Encoding.UTF8.GetString(payload.AsBytes());
        PlayerGameData receivedData = JsonUtility.FromJson<PlayerGameData>(dataStr);
        Debug.Log($"收到玩家数据:{receivedData.playerName},等级:{receivedData.playerLevel}");
        // 把收到的数据存到本地,之后可以做解锁道具、触发剧情这些逻辑
    }
}

// 自定义的玩家数据类,根据你的游戏需求改
[System.Serializable]
public class PlayerGameData
{
    public string playerName;
    public int playerLevel;
    public string favoriteCharacter;
    public bool hasUnlockedSecretItem;
}

小技巧:如果要传头像这类二进制数据,用Payload.FromFile()或者Payload.FromStream()就行,但Streetpass一般都是小数据,字节数组完全够用。

5. 断开连接和资源清理

当玩家离开范围或退出游戏时,记得清理资源:

public void StopAllStreetpassActions()
{
    Nearby.Connections.StopAdvertising();
    Nearby.Connections.StopDiscovery();
    Nearby.Connections.DisconnectFromAllEndpoints();
}

void OnApplicationQuit()
{
    StopAllStreetpassActions();
}

三、避坑指南(我踩过的那些破雷)

  • 权限问题:Android 12+除了Manifest里的权限,必须动态申请ACCESS_FINE_LOCATIONBLUETOOTH_SCANBLUETOOTH_ADVERTISE,不然Nearby直接罢工。
  • 测试环境:一定要用两台真实的Android设备测试!模拟器不支持Nearby的蓝牙/WiFi直连功能,我用模拟器测了半天没反应,换真机一秒就连上了。
  • 序列化一致性:两台设备的序列化/反序列化逻辑必须完全一致,比如你用JsonUtility,对方也得用同样的方式解析,不然会出现数据乱码或者解析失败。
  • 版本兼容:如果遇到API调用报错,先检查Nearby包的版本和Unity版本是否兼容,有时候降一个包版本就能解决问题。

最后

其实核心逻辑就是「初始化→找设备→连设备→传数据」,虽然官方文档确实拉胯,但把这些步骤跑通后,再套上你的游戏UI和剧情逻辑,完全能实现你要的Streetpass效果!要是中间卡在哪一步,随时喊我,我再给你捋细节~

火山引擎 最新活动