> ## 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 快速入門

> 在 Android Studio 中設定 PlayFab Services C SDK、新增原生程式庫，並從 Android 專案進行您的第一次 PlayFab API 呼叫。

# 快速入門：Android

開始使用適用於 Android 的 PlayFab Services SDK。請依照下列步驟將程式庫納入您的專案，並試用基本 PlayFab 功能的範例程式碼。

本快速入門可協助您使用 Android SDK 進行第一次 PlayFab API 呼叫。在繼續之前，請確定您已完成[快速入門：Game Manager](/zh-TW/services/playfab/live-service-management/gamemanager/quickstart) 中的步驟，以確保您擁有 PlayFab 帳戶並熟悉 PlayFab Game Manager。

## 需求

* [PlayFab 開發人員帳戶](https://developer.playfab.com)。
* 已安裝 [Android Studio](https://developer.android.com/studio)。

## 專案設定

從 [PlayFab SDK 發行頁面](https://github.com/PlayFab/PlayFabCSdk/releases/latest)將 PlayFab Android SDK 下載至您的專案。

### 將 PlayFab C SDK 整合至您自己的專案

接下來的步驟是假設您已使用 Android Studio 建立新專案而撰寫的。

#### 將二進位檔新增至您的遊戲

您需要將二進位檔的兩個部分整合至您的專案：共用物件檔案 (.so) 和 Android 封存檔案 (.aar)。您可以自行建置二進位檔，也可以從發行頁面下載。

#### 新增 .so 檔案

這些檔案會使用 CMake 整合至您的專案。

1. 解壓縮 PlayFab SDK for Android 發行版本，並將其內容放在您所需的目錄中。

2. 使用 **target\_include\_directories** 或其他對等函式，新增 PlayFab SDK 發行版本中「Include」底下的標頭：

```cmake theme={null}
TARGET_INCLUDE_DIRECTORIES(
    ${PROJECT_NAME}
    "Include"
)
```

3. 使用 **target\_link\_libraries** 或其他對等函式，將 .so 檔案的位置連結至您的專案。

   例如：

```cmake theme={null}
set(PLAYFAB_SERVICES_PATH "[LOCATION OF YOUR FILE]/libPlayFabServices.Android.so")

set(PLAYFAB_CORE_PATH "[LOCATION OF YOUR FILE]/libPlayFabCore.Android.so")

set(LIBHTTPCLIENT_PATH "[LOCATION OF YOUR FILE]/libHttpClient.Android.so")

TARGET_LINK_LIBRARIES(
    [YOUR PROJECT NAME]
    ${PLAYFAB_SERVICES_PATH}
    ${PLAYFAB_CORE_PATH}
    ${LIBHTTPCLIENT_PATH}
)
```

#### 新增 .aar 檔案

這些檔案會使用 Gradle 整合至您的專案。

1. 在應用程式層級的 Android 專案目錄中建立 libs 資料夾。以下範例顯示您的專案目錄現在應有的樣子：

<img src="https://mintcdn.com/microsoft-4404708b/N3T1ucKV7zIMBudj/images/playfab/sdks/c/android_1.png?fit=max&auto=format&n=N3T1ucKV7zIMBudj&q=85&s=298add66e2b7ab1a3f4b8508815f4f32" alt="專案目錄" width="652" height="496" data-path="images/playfab/sdks/c/android_1.png" />

2. 將 .aar 檔案複製到 libs 資料夾中。

3. 在應用程式層級的 build.gradle 檔案 (與 libs 資料夾位於相同目錄中的檔案) 中，將下列幾行新增至 dependencies 區段。第二行是 libHttpClient 所需的相依性。

```gradle theme={null}
implementation fileTree(dir: 'libs', include: ['*.aar'])
implementation 'com.squareup.okhttp3:okhttp:4.9.1'
```

## 初始化和登入

您的專案現在已完全設定為可使用適用於 Android 的 PlayFab Services SDK，請依照接下來的步驟，讓一些範例呼叫正常運作。

### 初始設定

您首先需要設定應用程式，使其具有 Android [活動](https://developer.android.com/reference/android/app/Activity)的執行個體。您還需要設定一個小型 C/C++ 應用程式，以透過 JNI (Java Native Interface) 使用 NDK。以下是一個可供參考的小型範例：[https://github.com/android/ndk-samples/tree/android-mk/hello-jni。](https://github.com/android/ndk-samples/tree/android-mk/hello-jni。)

此範例包含一個傳回 jstring 的原生方法：

```cpp theme={null}
jstring Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv* env, jobject thiz)
```

原生方法可用來取得 Java VM 和應用程式內容，這兩者都是初始化 PFServices 所需的項目。您可以建立類似的方法來進行初始化：

```cpp theme={null}
void Java_com_example_hellojni_HelloJni_InitializeApp(JNIEnv* env, jobject appContext)
```

接著可以使用 JNIEnv 變數擷取 Java VM。

```cpp theme={null}
    JavaVM* javaVM = nullptr;
    jint res = env->GetJavaVM(&javaVM);
    if (res != JNI_OK)
    {
        // error handling
    }
```

接下來，可以透過 jobject 參數取得應用程式內容。

```cpp theme={null}
    applicationContext = env->NewGlobalRef(appContext);
```

現在您已儲存這兩個變數，我們就可以開始進行呼叫。

### 標頭

納入 **PFServices.h** 以存取所有隨附的 PlayFab 功能：

```cpp theme={null}
#include <playfab/services/PFServices.h>
```

### 初始化

PlayFab 初始化需要兩個函式呼叫：**PFServicesInitialize** 和 **PFServiceConfigCreateHandle**。此初始化的結果是一個 **PFServiceConfigHandle**。您會將此控制代碼提供給後續的登入呼叫，以將呼叫導向 PlayFab 後端中正確的遊戲。

```cpp theme={null}
    HCInitArgs initArgs;
    // Use the Java VM and application context from earlier
    initArgs.javaVM = javaVm;
    initArgs.applicationContext = applicationContext;

    HRESULT hr = PFServicesInitialize(nullptr, &initArgs); // Add your own error handling when FAILED(hr) == true

    PFServiceConfigHandle serviceConfigHandle{ nullptr };

    hr = PFServiceConfigCreateHandle(
            "https://ABCDEF.playfabapi.com",    // PlayFab API endpoint - obtained in the Game Manager
            "ABCDEF",                           // PlayFab Title id - obtained in the Game Manager
            &serviceConfigHandle);
```

### 登入

取得 **PFServiceConfigHandle** 之後，您就可以使用它進行玩家登入呼叫。在 SDK 中，使用 **PFAuthenticationLoginWith\*Async** 方法，例如 **PFAuthenticationLoginWithCustomIDAsync**。此函式可讓您使用自訂識別碼將玩家登入 PlayFab。

進行登入呼叫之後，您可以使用 **XAsyncGetStatus** 檢查呼叫的狀態。狀態一開始為 **E\_PENDING**，並在呼叫順利完成後變更為 **S\_OK**。如果呼叫因故失敗，狀態會反映該失敗。所有 PlayFab Services 呼叫的錯誤處理都是以這種方式運作。

除了 **S\_OK** 結果之外，您還會取回 **PFEntityHandle**。您可以使用此控制代碼，以已登入玩家的身分進行後續 PlayFab 呼叫。它包含以該玩家身分向 PlayFab 服務進行驗證所需的任何資料。

```cpp theme={null}
    PFAuthenticationLoginWithCustomIDRequest request{};
    request.createAccount = true;
    request.customId = "player1";

    XAsyncBlock async{};
    HRESULT hr = PFAuthenticationLoginWithCustomIDAsync(serviceConfigHandle, &request, &async); // Add your own error handling when FAILED(hr) == true
    hr = XAsyncGetStatus(&async, true); // This is doing a blocking wait for completion, but you can use the XAsyncBlock to set a callback instead for async style usage

    std::vector<char> loginResultBuffer;
    PFAuthenticationLoginResult const* loginResult;
    size_t bufferSize;
    hr = PFAuthenticationLoginWithCustomIDGetResultSize(&async, &bufferSize);
    loginResultBuffer.resize(bufferSize);

    PFEntityHandle entityHandle{ nullptr };
    hr = PFAuthenticationLoginWithCustomIDGetResult(&async, &entityHandle, loginResultBuffer.size(), loginResultBuffer.data(), &loginResult, nullptr);
```

## 服務呼叫

將玩家登入之後，您現在可以對 PlayFab 後端進行呼叫。以下範例示範如何呼叫以取得目前玩家儲存在 PlayFab 中的檔案。

### 取得 EntityKey

對於某些 PlayFab 呼叫而言，知道玩家的 **PFEntityKey** 會很有用。取得 **PFEntityToken** 之後，您可以使用 **PFEntityGetEntityKey** 擷取 **PFEntityKey**。

```cpp theme={null}
    PFEntityKey const* pEntityKey{};
    std::vector<char> entityKeyBuffer;
    size_t size{};
    HRESULT hr = PFEntityGetEntityKeySize(entityHandle, &size); // Add your own error handling when FAILED(hr) == true

    entityKeyBuffer.resize(size);
    hr = PFEntityGetEntityKey(entityHandle, entityKeyBuffer.size(), entityKeyBuffer.data(), &pEntityKey, nullptr);
```

### 呼叫 GetFiles

所有 PlayFab 呼叫都遵循類似的模式：準備要求物件、進行呼叫 (使用登入取得的 **PFEntityHandle**)、建立接收回應的物件，然後呼叫 **GetResult** 函式來填入新建立的容器。

```cpp theme={null}
    XAsyncBlock async{};
    PFDataGetFilesRequest requestFiles{};
    requestFiles.entity = pEntityKey;

    HRESULT hr = PFDataGetFilesAsync(entityHandle, &requestFiles, &async); // Add your own error handling when FAILED(hr) == true
    hr = XAsyncGetStatus(&async, true); // This is doing a blocking wait for completion, but you can use the XAsyncBlock to set a callback instead for async style usage

    size_t resultSize;
    hr = PFDataGetFilesGetResultSize(&async, &resultSize);

    std::vector<char> getFilesResultBuffer(resultSize);
    PFDataGetFilesResponse* getFilesResponseResult{ nullptr };
    hr = PFDataGetFilesGetResult(&async, getFilesResultBuffer.size(), getFilesResultBuffer.data(), &getFilesResponseResult, nullptr);
```

## 清除

當您的遊戲準備關閉，或您因其他原因需要清除 PlayFab 時，請確定關閉所有開啟的控制代碼，並呼叫 **PFServicesUninitializeAsync**。

```cpp theme={null}
    PFEntityCloseHandle(entityHandle);
    entityHandle = nullptr;

    PFServiceConfigCloseHandle(serviceConfigHandle);
    serviceConfigHandle = nullptr;

    XAsyncBlock async{};
    HRESULT hr = PFServicesUninitializeAsync(&async); // Add your own error handling when FAILED(hr) == true
    hr = XAsyncGetStatus(&async, true); // This is doing a blocking wait for completion, but you can use the XAsyncBlock to set a callback instead for async style usage
```

## 非同步 API 模式

PlayFab Services SDK 遵循 GDK 中實作的[非同步程式設計模型](https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/system/overviews/async-programming-model)。此程式設計模型涉及使用 [XAsync 程式庫](/zh-TW/build/core-features/common/async/async-libraries/async-library-xasync)所提供的工作和工作佇列。此模型與其他 GDK 函式和延伸模組 (例如 XBOX 服務 API) 一致。雖然它確實帶來一些複雜性，但也讓您能高度控制非同步作業。

此範例示範如何對 **PFDataGetFilesAsync** 進行非同步呼叫。

```cpp theme={null}
    auto async = std::make_unique<XAsyncBlock>();
    async->callback = [](XAsyncBlock* async)
    {
        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ async }; // take ownership of XAsyncBlock

        size_t resultSize;
        HRESULT hr = PFDataGetFilesGetResultSize(async, &resultSize);
        if (SUCCEEDED(hr))
        {
            std::vector<char> getFilesResultBuffer(resultSize);
            PFDataGetFilesResponse* getFilesResponseResult{ nullptr };
            PFDataGetFilesGetResult(async, getFilesResultBuffer.size(), getFilesResultBuffer.data(), &getFilesResponseResult, nullptr);
        }
    };

    PFDataGetFilesRequest requestFiles{};
    requestFiles.entity = m_pEntityKey;
    HRESULT hr = PFDataGetFilesAsync(m_entityHandle, &requestFiles, async.get());
    if (SUCCEEDED(hr))
    {
        async.release(); // at this point, the callback will be called so release the unique ptr
    }

```

## 錯誤處理

已完成的 **XAsync** 作業會傳回 HTTP 狀態碼。呼叫 **XAsyncGetStatus()** 或其中一個 **PF\*Get()** API 時，錯誤狀態碼會以失敗 **HRESULT** 的形式呈現，例如 **HTTP\_E\_STATUS\_NOT\_FOUND**。

若要查看服務傳回的詳細錯誤訊息，請參閱下一節的偵錯說明。在開發期間，這些詳細的錯誤訊息有助於您進一步了解 PlayFab 服務如何回應來自用戶端的要求。

## 偵錯

若要查看 PlayFab Services SDK 中任何呼叫的結果並加以偵錯，最簡單的方式是啟用[偵錯追蹤](/zh-TW/services/playfab/sdks/c/tracing)。啟用偵錯追蹤後，您既可以在偵錯工具輸出視窗中查看結果，也可以將結果連結至遊戲本身的記錄。

## 參考

[API 參考文件](/zh-TW/services/playfab/api-references/c/pfauthentication/pfauthentication_members)


## Related topics

- [PlayFab 支援的語言](/zh-TW/services/playfab/sdks/languages/index.md)
- [PlayFab Party SDK](/zh-TW/services/playfab/multiplayer/networking/party-sdks/overview.md)
- [Party 快速入門](/zh-TW/services/playfab/multiplayer/networking/quickstart.md)
- [快速入門](/zh-TW/services/playfab/economy-monetization/economy-v2/quickstart.md)
- [適用於原生與 Android Studio 的 Java 快速入門](/zh-TW/services/playfab/sdks/java/quickstart.md)
