> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Android 快速入门

> PlayFab Party SDK 的 Android 专用设置,包括 NDK 要求、JNI 初始化,以及清单中的音频和麦克风权限。

本文档列出了将 PlayFab Party 集成到你的 Android 应用程序中所需的基本先决条件和要求。根据本文档设置好系统后,请查看 [PlayFab Party 快速入门](/services/playfab/multiplayer/networking/quickstart),以完成 PlayFab Party 构建模块的设置。

## 先决条件

在开始本教程之前,请确保满足以下先决条件:

1. 你已创建 [PlayFab 开发者帐户](https://developer.playfab.com)。

2. 你已创建 PlayFab Title,并且该 Title 已被列入 PlayFab Party 的允许列表。

3. 你已安装 Android Studio 3.2 或更高版本。

4. 你的应用面向 Android 4.4(KitKat)或更高版本。

5. 你已安装 Android NDK 18.1.5063045 或更高版本。

6. 你有权访问 [PlayFab Party 平台仓库](https://github.com/PlayFab/PlayFabParty/releases)。

7. 你已创建 Android 签名证书,并使用该证书配置为部署对应用进行了签名。

## 包含所需的库和头文件

你需要包含 [PlayFab Party 分发仓库](https://github.com/PlayFab/PlayFabParty)中的以下头文件。

LIB 文件

1. libParty.a
2. libcrypto.a
3. libssl.a

<Note>
  SSL 库基于 [Open SSL 1.1.1b-dev 版本](https://github.com/openssl/openssl/tree/OpenSSL_1_1_1-stable)构建。请使用 1.1.1b-dev 或更高版本的 openSSL。
</Note>

头文件

[Party 头文件](https://github.com/PlayFab/PlayFabParty/tree/master/include)

<Note>
  除了上述 lib 文件和头文件之外,你还需要 PlayFab SDK 的 lib 和头文件,以及应用所需的任何其他平台特定依赖项。有关更多信息,请查看 Android 示例的项目文件组织。
</Note>

## 让 PlayFab Party 在 Android 上工作的步骤

由于核心 Party 库是使用 C++ 编写的,我们需要制作一个简单的 JNI 包装类以访问 Party 库功能。总体而言,你需要一个可访问 Party API 方法的类,用于创建网络、连接到网络以及在网络上发送消息。我们在演示应用中通过 [NetworkManager Java 类](https://github.com/PlayFab/PlayFabParty/blob/docs/android/PartySample/demo/src/main/java/com/microsoft/playfab/party/sdk/NetworkManager.java)实现了这一点。

```java theme={null}

import android.util.Log;

public class NetworkManager {
    static {
        System.loadLibrary("partysample");
    }

    private MessageManager messageManager;

    private static NetworkManager networkManager;

    private NetworkManager() {
    }

    public static NetworkManager getInstance() {
        if (networkManager == null) {
            networkManager = new NetworkManager();
        }
        return networkManager;
    }

    public native boolean initialize(String name);

    public native boolean createAndConnectToNetwork(String type, String languageCode);

    public native boolean joinNetwork(String networkId);

    public native void leaveNetwork();

    public native void sendTextMessage(String message, boolean isTTS);

    public native void doWork();

    public native void getPlayerState();

    public native void setLanguage(int idx);

    public native void setPlayFabTitleID(String titleID);

    public void onNetworkCreated(String network) {
        Log.d(getClass().getSimpleName(), "onNetworkCreated: " + network);
        getMessageManager().sendNetworkCreatedMessage(network);
        getMessageManager().sendErrorMessage("Connected to network: " + network);
    }

    public void onMessageReceived(String sender, String message) {
        Log.d(getClass().getSimpleName(), "onMessageReceived: " + sender + ": " + message);
        getMessageManager().sendTextMsgReceivedMessage(sender, message, false);
    }

    public void onTranscriptMessageReceived(String sender, String message) {
        Log.d(getClass().getSimpleName(), "onTranscriptMessageReceived: " + sender + ": " + message);
        getMessageManager().sendTextMsgReceivedMessage(sender, message, true);
    }

    public void onPlayerJoined(String playerId, String name) {
        Log.d(getClass().getSimpleName(), "onPlayerJoined: " + playerId + ": " + name);
        getMessageManager().sendPlayerJoinMessage(playerId, name);
    }

    public void onPlayerLeft(String playerId) {
        Log.d(getClass().getSimpleName(), "onPlayerLeft: " + playerId);
        getMessageManager().sendPlayerLeftMessage(playerId);
    }

    public void toastMessage(String message) {
        getMessageManager().toastMessage(message);
    }

    public void resetChat(String error) {
        getMessageManager().sendResetMessage(error);
    }
    public void resetMessage() {
        getMessageManager().sendResetMessage("Left");
    }

    public void addErrorMessage(String message) {
        getMessageManager().sendErrorMessage(message);
    }

   public void updatePlayerState(String playerId, String state) {
        Log.d(getClass().getSimpleName(), "updatePlayerState: " + playerId + ": " + state);
        getMessageManager().sendPlayerStatusMessage(playerId, state);
    }

    public MessageManager getMessageManager() {
        return MessageManager.getInstance();
    }

}
```

上面的 JNI 桥接由一个纯 C++ 实现文件提供支持,该文件调用 [NetworkManager.cpp](https://github.com/PlayFab/PlayFabParty/blob/docs/android/PartySampleNetworkCommon/lib/NetworkManager.cpp),而后者又调用 Party API。

下面是展示各个层级的示例代码段:

NetworkManager Java 接口公开了一种加入 Party Network 的方法。

```java theme={null}
public native boolean joinNetwork(String networkId);
```

`joinNetwork` 的实现位于 [PartyDemo.cpp](https://github.com/PlayFab/PlayFabParty/blob/docs/android/PartySample/demo/src/main/cpp/PartyDemo.cpp) 中的 C++ 层,如下所示。

```cpp theme={null}
JNIEXPORT jboolean JNICALL
    Java_com_microsoft_playfab_party_sdk_NetworkManager_joinNetwork(
        JNIEnv* env,
        jobject thiz,
        jstring networkId
        )
    {
        if (g_isRunning && g_initializeCompleted)
        {
            Managers::Get<NetworkManager>()->Initialize(g_playfabTitleId.c_str());
            const char* networkNameCStr = env->GetStringUTFChars(networkId, NULL);
            g_networkName = networkNameCStr;
            env->ReleaseStringUTFChars(networkId, networkNameCStr);
            g_isSpinDone = false;
            Managers::Get<PlayFabManager>()->GetDescriptor(
                    g_networkName,
                    [](std::string networkDescriptor)
                    {
                        SendSysLogToUI("OnGetDescriptorForConnectTo : %s", networkDescriptor.c_str());
                        g_networkDescriptor = networkDescriptor;
                        ReleaseSpin();
                    }
            );

            HoldSpin();
            // When network connection is not stable, waiting for ConnectToNetwork callback will cost longer time.
            // To avoid App UI busy waiting, return to UI after ConnectToNetwork returns.
            Managers::Get<NetworkManager>()->ConnectToNetwork(
                g_networkName.c_str(),
                g_networkDescriptor.c_str(),
                []()
                {
                    OnNetworkConnected(g_networkName);
                    SendSysLogToUI("OnConnectToNetwork succeeded");
                },
                [](PartyError error)
                {
                    SendSysLogToUI("OnConnectToNetworkFailed %s", GetErrorMessage(error));
                    ResetChat(GetErrorMessage(error));
                });

            return true;
        }
        else
        {
            SendSysLogToUI("Please waiting for initialization done.");
            return false;
        }
    }
```

在上面的代码段中,`joinNetwork` 调用 `NetworkManager::CreateAndConnectToNetwork()`,后者又调用 [Party.h](https://github.com/PlayFab/PlayFabParty/blob/docs/include/Party.h) 中公开的原始 Party API。

```cpp theme={null}
void 
NetworkManager::CreateAndConnectToNetwork(
    const char *networkId, 
    std::function<void(std::string)> callback, 
    std::function<void(PartyError)> errorCallback
    )
{
    DEBUGLOG("NetworkManager::CreateAndConnectToNetwork()\n");

    // Set the maximum number of devices allowed in a network to 16 devices
    constexpr uint8_t c_maxSampleNetworkDeviceCount = 16;
    static_assert(c_maxSampleNetworkDeviceCount <= c_maxNetworkConfigurationMaxDeviceCount, "Must be less than or equal to c_maxNetworkConfigurationMaxDeviceCount.");

    // Initialize network configuration for Party Network.
    PartyNetworkConfiguration cfg = {};
    cfg.maxDeviceCount = c_maxSampleNetworkDeviceCount;
    cfg.maxDevicesPerUserCount = 1;
    cfg.maxEndpointsPerDeviceCount = 1;
    cfg.maxUserCount = c_maxSampleNetworkDeviceCount;
    cfg.maxUsersPerDeviceCount = 1;

    //Get the uid from the local chat control
    PartyString uid = nullptr;
    PartyError err = m_localUser->GetEntityId(&uid);

    if (PARTY_FAILED(err))
    {
        DEBUGLOG("GetUserIdentifier failed: %s\n", GetErrorMessage(err));
        errorCallback(err);
        return;
    }

    // Setup the network invitation configuration to use the network id as an invitation id and allow anyone to join.
    PartyInvitationConfiguration invitationConfiguration{
        networkId,                                  // invitation identifier
        PartyInvitationRevocability::Anyone,        // revokability
        0,                                          // authorized user count
        nullptr                                     // authorized user list
    };

    // Initialize an empty network descriptor to hold the result of the following call.
    PartyNetworkDescriptor networkDescriptor = {};

    // Create a new network descriptor
    err = PartyManager::GetSingleton().CreateNewNetwork(
        m_localUser,                                // Local User
        &cfg,                                       // Network Config
        0,                                          // Region List Count
        nullptr,                                    // Region List
        &invitationConfiguration,                   // Invitation configuration
        nullptr,                                    // Async Identifier
        &networkDescriptor,                         // OUT network descriptor
        nullptr                                     // applied initialinvitationidentifier.
    );

    if (PARTY_FAILED(err))
    {
        DEBUGLOG("CreateNewNetwork failed: %s\n", GetErrorMessage(err));
        errorCallback(err);
        return;
    }

    // Connect to the new network
    if (InternalConnectToNetwork(networkDescriptor, networkId, errorCallback))
    {
        m_state = NetworkManagerState::WaitingForNetwork;
        m_onnetworkcreated = callback;
        m_onnetworkcreatederror = errorCallback;
        m_onnetworkconnectedError = errorCallback;
    }
}
```

以类似方式,NetworkManager JNI 接口中的每个方法都通过 PartyDemo 和 NetworkManager 映射到 Party API。

## 后续步骤

在本文中,我们了解了如何开始将 Party 库集成到你的 Android 应用程序中。请参阅 [PlayFab Party 快速入门](/services/playfab/multiplayer/networking/quickstart),以完成 PlayFab Party 其余构建模块的设置。


## Related topics

- [Android 快速入门](/zh-CN/services/playfab/sdks/c/quickstart-android.md)
- [使用 Economy v2、Unity IAP 和 Android 快速入门](/zh-CN/services/playfab/economy-monetization/economy-v2/tutorials/getting-started-with-unity-and-android.md)
- [PlayFab 支持的语言](/zh-CN/services/playfab/sdks/languages/index.md)
- [PlayFab Party SDK](/zh-CN/services/playfab/multiplayer/networking/party-sdks/overview.md)
- [快速入门](/zh-CN/services/playfab/economy-monetization/economy-v2/quickstart.md)
