# 代码集成

> Implement Remote Config in your game code using the RemoteConfig API.

`RemoteConfig` API 包含在 `Unity.Services` 命名空间中，您必须将其加入您的游戏脚本中。有关其类和方法的更多信息，请参阅 [Remote Config 脚本 API](https://docs.unity3d.com/Packages/com.unity.remote-config@latest) 和 [Remote Config Runtime 脚本 API](https://docs.unity3d.com/Packages/com.unity.remote-config-runtime@latest/index.html?subfolder=/api/index.html) 文档。

## 实现自定义属性##implementing-custom-attributes

要为[游戏覆盖条件](./game-overrides-and-settings.md#condition)提供自定义属性，请在游戏脚本中实现以下 `struct` 变量：

* 如果您的应用程序使用自己的跟踪方法，则通过 `SetCustomUserID` 方法使用 `Delivery` 结构来提供自定义玩家 ID 属性。如果没有开发者定义的属性，Remote Config 将自动生成 ID。
* 使用 `userAttributes` 结构来提供自定义**用户**类别属性。
* 使用 `appAttributes` 结构来提供自定义**应用**类别属性。
* 使用 `filterAttributes` 结构来提供自定义**过滤器**类别属性，以减少有效负载。

**注意**：自定义属性完全是可选的。您可以在没有这些结构的情况下实现 Unity Remote Config，并针对游戏覆盖条件使用预定义的 Unity 属性。有关属性类别的更多信息，请参阅关于[条件](./game-overrides-and-settings.md#condition)的文档。

首先，为实现自定义属性和阻止函数的脚本创建框架：

```c#
using UnityEngine;
using Unity.Services.RemoteConfig;
using Unity.Services.Authentication;
using Unity.Services.Core;
using System.Threading.Tasks;

public class RemoteConfigExample : MonoBehaviour {

    public struct userAttributes {
      // Optionally declare variables for any custom user attributes:
        public bool expansionFlag;
    }

    public struct appAttributes {
      // Optionally declare variables for any custom app attributes:
        public int level;
        public int score;
        public string appVersion;
    }

    public struct filterAttributes {
      // Optionally declare variables for attributes to filter on any of following parameters:
        public string[] key;
        public string[] type;
        public string[] schemaId;
    }

    // Optionally declare a unique assignmentId if you need it for tracking:
    public string assignmentId;

    // Declare any Settings variables you’ll want to configure remotely:
    public int enemyVolume;
    public float enemyHealth;
    public float enemyDamage;


    // The Remote Config package depends on Unity's authentication and core services.
    // These dependencies require a small amount of user code for proper configuration.
    async Task InitializeRemoteConfigAsync()
    {
            // initialize handlers for unity game services
            await UnityServices.InitializeAsync();

            // options can be passed in the initializer, e.g if you want to set AnalyticsUserId or an EnvironmentName use the lines from below:
            // var options = new InitializationOptions()
            // .SetEnvironmentName("testing")
            // .SetAnalyticsUserId("test-user-id-12345");
            // await UnityServices.InitializeAsync(options);

            // remote config requires authentication for managing environment information
            if (!AuthenticationService.Instance.IsSignedIn)
            {
                await AuthenticationService.Instance.SignInAnonymouslyAsync();
            }
    }

    async Task Awake () {
        // In this example, you will fetch configuration settings on Awake.
    }

    // Create a function to set your variables to their keyed values:
    void ApplyRemoteConfig (ConfigResponse configResponse) {
        // You will implement this in the final step.
    }
}
```

## 在运行时获取并应用设置##fetching-and-applying-settings-at-runtime

接下来，实现您的 Remote Config 支持函数并在运行时调用这些函数，以便从服务检索键值对，然后将它们映射到相应的变量。

Remote Config 服务返回 [`RemoteConfigService.Instance`](https://docs.unity3d.com/Packages/com.unity.remote-config-runtime@latest/index.html?subfolder=/api/Unity.Service.RemoteConfig.RemoteConfigService.html) 对象，用于在运行时获取并应用您的配置设置。在此示例中，您将使用它来从远程服务获取键值对，并在检索时调用您的 `ApplyRemoteConfig` 函数。`ApplyRemoteConfig` 接收一个 [`ConfigResponse`](https://docs.unity3d.com/Packages/com.unity.remote-config-runtime@latest/index.html?subfolder=/api/Unity.Service.RemoteConfig.ConfigResponse.html) 结构，该结构表示对获取请求的响应，并使用 [`RemoteConfigService.Instance.appConfig`](https://docs.unity3d.com/Packages/com.unity.remote-config-runtime@latest/index.html?subfolder=/api/Unity.Service.RemoteConfig.RemoteConfigService.appConfig.html) 方法来应用设置。

```c#
    // Retrieve and apply the current key-value pairs from the service on Awake:
    async Task Awake () {

        // initialize Unity's authentication and core services, however check for internet connection
        // in order to fail gracefully without throwing exception if connection does not exist
        if (Utilities.CheckForInternetConnection()) 
        {
            await InitializeRemoteConfigAsync();
        }

        // Add a listener to apply settings when successfully retrieved:
        RemoteConfigService.Instance.FetchCompleted += ApplyRemoteConfig;

        // you can set the user’s unique ID:
        // RemoteConfigService.Instance.SetCustomUserID("some-user-id");

        // you can set the environment ID:
        // RemoteConfigService.Instance.SetEnvironmentID("an-env-id");

        // Fetch configuration settings from the remote service, they must be called with the attributes structs (empty or with custom attributes) to initiate the WebRequest.
        await RemoteConfigService.Instance.FetchConfigsAsync(new userAttributes(), new appAttributes());

        // Example on how to fetch configuration settings using filter attributes:
        // var fAttributes = new filterAttributes();
        // fAttributes.key = new string[] { "sword","cannon" };
        // RemoteConfigService.Instance.FetchConfigs(new userAttributes(), new appAttributes(), fAttributes);

        // Example on how to fetch configuration settings if you have dedicated configType:
        // var configType = "specialConfigType";
        // Fetch configs of that configType
        // RemoteConfigService.Instance.FetchConfigs(configType, new userAttributes(), new appAttributes());
        // Configuration can be fetched with both configType and fAttributes passed
        // RemoteConfigService.Instance.FetchConfigs(configType, new userAttributes(), new appAttributes(), fAttributes);

        // All examples from above will also work asynchronously, returning Task<RuntimeConfig>
        // await RemoteConfigService.Instance.FetchConfigsAsync(new userAttributes(), new appAttributes());
        // await RemoteConfigService.Instance.FetchConfigsAsync(new userAttributes(), new appAttributes(), fAttributes);
        // await RemoteConfigService.Instance.FetchConfigsAsync(configType, new userAttributes(), new appAttributes());
        // await RemoteConfigService.Instance.FetchConfigsAsync(configType, new userAttributes(), new appAttributes(), fAttributes);

    }

    void ApplyRemoteConfig (ConfigResponse configResponse) {
        // Conditionally update settings, depending on the response's origin:
        switch (configResponse.requestOrigin) {
            case ConfigOrigin.Default:
                Debug.Log ("No settings loaded this session and no local cache file exists; using default values.");
                break;
            case ConfigOrigin.Cached:
                Debug.Log ("No settings loaded this session; using cached values from a previous session.");
                break;
            case ConfigOrigin.Remote:
                Debug.Log ("New settings loaded this session; update values accordingly.");
                break;
        }

        enemyVolume = RemoteConfigService.Instance.appConfig.GetInt("enemyVolume");
        enemyHealth = RemoteConfigService.Instance.appConfig.GetInt("enemyHealth");
        enemyDamage = RemoteConfigService.Instance.appConfig.GetFloat("enemyDamage");
        assignmentId = RemoteConfigService.Instance.appConfig.assignmentId;

        // These calls could also be used with the 2nd optional arg to provide a default value, e.g:
        // enemyVolume = RemoteConfigService.Instance.appConfig.GetInt("enemyVolume", 100);
    }
```

## 访问具有特定配置类型的配置##accessing-configs-with-particular-config-types

相应配置类型的所有设置都将正确地储存在缓存中。您可以通过传递配置类型来访问这些设置，例如：

```c#
RemoteConfigService.Instance.GetConfig("settings");
RemoteConfigService.Instance.GetConfig("specialConfigType");
```

## 元数据参数##metadata-parameters

收到每个请求时，我们都会在后端创建一个分配事件。

在对请求的响应中，与 `configs` 代码块一起返回一个 `metadata` 代码块，其中包括以下参数：


**Frame:**
![MetaDataBlock](/api/media?file=/remote-config/media/images/meta-data-block.png)

* 每个分配事件都会创建 `assignmentId`，它用于跟踪事件和最终的用户细分
* `environmentId` 表示发生分配的环境
* `configAssignmentHash` 在分配时创建，表示该特定分配的唯一签名

`configAssignmentHash` 可以通过 `appConfig` 进行访问：

```c#
RemoteConfigService.Instance.appConfig.configAssignmentHash
```

在确定要使用的 `configAssignmentHash` 后，可以通过使用 `SetConfigAssignmentHash()` 方法来在有效负载中将其传递到后端：

```c#
RemoteConfigService.Instance.SetConfigAssignmentHash("4d1064c5198a26f073fe8301da3fc5ead35d20d1"); 
```

如果将 `configAssignmentHash` 传递到后端，后端将返回该特定 `configAssignmentHash` 创建时存在的配置。

`configAssignmentHash` 生命周期的 TTL 为 56 小时。经过该时间后，可以再次请求 `configAssignmentHash`，而 TTL 将再次重置为 56 小时。

## 其他注意事项##working-with-templates

### 利用 JSON 类型的 Settings 来覆盖对象##utilizing-setting-of-type-json-for-overwriting-objects

假设我们的代码中具有如下 `CubeInfo` 类：

```c#
[System.Serializable]
public class CubeInfo
{
    public float rotateX = 10f;
    public float rotateY = 10f;
    public float rotateZ = 10f;
    public float rotSpeed = 1.0f;
    public Color color = Color.white;
}

```

JSON 编辑器模式窗口支持以下类型的 JSON 转换：

* 文本资源
* 脚本化对象
* 附加到游戏对象的自定义脚本

如果要使用文本资源，我们可以设置在结构上与 `CubeInfo` 类匹配的 Settings：


**Frame:**
![CubeJsonTextAsset](/api/media?file=/remote-config/media/images/cube-json-text-asset.png)

对于脚本化对象，单击选择框旁边的右上方圆点。选择一个脚本化对象后，该对象会自动转换为 json：


**Frame:**
![CubeJsonSO](/api/media?file=/remote-config/media/images/cube-json-so.png)

如果从场景中选择游戏对象，则将显示一个额外的下拉选单，其中包括附加到该游戏对象的所有 Monobehavior 自定义脚本。您选择的对象会转换为 JSON：


**Frame:**
![CubeJsonCustomScript](/api/media?file=/remote-config/media/images/cube-json-custom-script.png)

要在运行时将这些设置应用到 CubeInfo 对象，请使用 [JsonUtility](https://docs.unity3d.com/ScriptReference/JsonUtility.html) 类来完成该操作：

```c#
case ConfigOrigin.Remote:
    var jsonCubeString = RemoteConfigService.Instance.appConfig.GetJson("jsonCubeString");
    JsonUtility.FromJsonOverwrite(jsonCubeString, CubeInfo);
```

### 安全##security

Unity 用来下载 Remote Config 数据的 Web 服务是只读的，但并不安全。这意味着第三方或许能够查看您的 Remote Config 数据。请勿将敏感或机密信息存储在您的配置设置中。同样，最终用户也可以读取和修改保存的设置文件（尽管在下次会话启动时，Remote Config 会在有可用的互联网连接时覆盖任何修改）。

### 平台支持##platform-support

当前版本的 Remote Config Runtime 经过测试可以在以下平台上成功运行：

桌面：

* Windows (PC)
* Mac
* Linux 平台

移动：

* iOS
* Android

有关 Remote Config 的控制台支持的信息，请联系我们的[支持团队](https://support.unity.com/hc/en-us/requests/new?ticket_form_id=360001936712)。
