遠程配置可以使我們在不重新發(fā)包的前提下來實現(xiàn)如下功能:
- 根據(jù)玩家的地區(qū)和語言進行更人性化的設(shè)置
- 調(diào)整用戶的游戲難度,使之有更好的游戲體驗
- 在特殊節(jié)日打開對應(yīng)的特殊事件
- 運行不同的顏色和樣式方案,找到用戶偏好的趨勢
- 監(jiān)控用戶群像時,逐步打開新的功能
- 針對用戶設(shè)備性能,提供最合適的游戲配置
以上只是列出了廣為人知的幾個功能,通過這些手段我們可以更好的改進產(chǎn)品,提高用戶粘度.Unity開發(fā)除了使用 Firebase 的遠程配置,Unity官方在今年的二月份發(fā)布了自己的遠程配置服務(wù): Unity Remote Config,目前已經(jīng)更新到了1.0.8版本,下面我會結(jié)合官方文檔,介紹下這個服務(wù)的使用.
1. 使項目關(guān)聯(lián)Unity Services
項目要使用Unity Services,需要一個Unity Services Project ID,通過該ID把項目連接到Unity Services,使之可以使用Services中的各項功能,比如 IAP, Ads 以及 Remote Config 等.可以在Unity編輯器內(nèi)快速創(chuàng)建這個ID.通過 Window > General > Services 或者點擊工具欄中下方標記出的圖標
來打開Unity Services界面.首先需要選擇 Organization ,一般是你在注冊Unity時使用的賬號.
然后需要選擇一個 Project Name ,默認是你當前打開的項目:
至此,Unity Services Project ID創(chuàng)建完畢,現(xiàn)在可以使用 Unity Services 了.
更多信息請查閱: 創(chuàng)建Unity Services Project ID
2. 下載Unity Remote Config Package并配置環(huán)境
打開 Window > Package Manager ,搜索 Remote 關(guān)鍵字找到對應(yīng)的Package下載.
Remote Config 有兩種配置環(huán)境, Development 和 Release ,顧名思義,一種是測試環(huán)境,一種是生產(chǎn)環(huán)境,兩種環(huán)境下對應(yīng)的配置項是獨立的,如果要在手機上測試 Development 環(huán)境的配置,在打包時需要打開 Development Build 開關(guān),這樣在手機上啟動應(yīng)用后從服務(wù)器拉取的才是 Development 下的配置.默認是 Release 環(huán)境配置.
Package下載完成后,我們就可以在 Window 列表下看到它:
3. Settings Config(配置) and Rules(規(guī)則)
我們先來說明下這兩個概念:
- Settings Config: 遠程配置的基本單元,是一個 key/value 鍵值對,根據(jù)產(chǎn)品需求來定義該字段,代表應(yīng)用啟動后可能會被遠程覆蓋的字段.
- Rules: 配置啟用規(guī)則,每種規(guī)則都可以包含不同的 Settings Config ,并決定這些配置在何種條件下啟用.
在需求定下來之后, Settings Config 的值要確定,開發(fā)人員可以根據(jù)這些值來進行邏輯布局,而 Rules 則可以由PM根據(jù)要測試的情景在 Dashboard 中創(chuàng)建或者修改.
只看概念可能不太了解,我們通過實際操作來說明.
配置和規(guī)則的設(shè)置可以在Unity編輯器內(nèi)部,也可以在網(wǎng)頁上.點擊 Window > Remote Config可以打開本地設(shè)置界面.需要注意的是: 在本地的編輯需要推送到服務(wù)器才會被應(yīng)用拉取到.
Dashboard中的選項跟在Unity編輯器中的基本是一一對應(yīng)的,大家可以自己對照下.
我們這里就以Unity編輯器中的界面來講解.
這里重點講解一下 Conditon 選項:
規(guī)則使用 Conditon 來定位該規(guī)則應(yīng)用的用戶群體, Conditon 是 JEXL 表達式,這種表達式的更多信息請查閱:JEXL語法
有三種類別的條件可以設(shè)置:
- 根據(jù)用戶信息,使用內(nèi)置的 user 字段和點語法,比如我們要對用戶年齡大于18的人群使用該規(guī)則,可以設(shè)置 Conditon 為
user.age>18
,關(guān)于 age 的定義見下一章. - 根據(jù)應(yīng)用信息,使用內(nèi)置的 app 字段和點語法,比如要對應(yīng)用的level大于2的人群使用該規(guī)則,可以設(shè)置 Conditon 為
app.level>2
,關(guān)于 level 的定義見下一章. - 使用Unity預(yù)定義的屬性:
屬性 | 描述 | 例 |
---|---|---|
unity.appBuildVersion |
應(yīng)用程序的構(gòu)建版本號(Edit > Project Settings > Player)。 | unity.appBuildVersion == '1' |
unity.appVersion |
應(yīng)用程序的版本號(Edit > Project Settings > Player)目溉。 | unity.appVersion == '1.0' |
unity.cpu |
cpu處理器的名稱症杏。 | unity.cpu == 'Intel(R) Core(TM) i7-7920 HQ CPU @ 3.10GHz' |
unity.cpuFrequency |
運行設(shè)備的處理器頻率(MHz)据某。 | unity.cpuFrequency >= 3100 |
unity.country |
國家/地區(qū)編碼漱病。此屬性使用 ISO 3166-1 alpha2 國家/地區(qū)代碼。 | unity.country == 'US' |
unity.language |
語言編碼冕茅。此屬性使用 ISO 639-1 語言代碼落午。 | unity.language == 'en' |
unity.osVersion |
運行應(yīng)用程序的設(shè)備的操作系統(tǒng)版本。 | unity.osVersion == 'Mac OS X 10.14.4' |
unity.platform |
適用的設(shè)備或平臺鲫咽∏┰撸可以是以下值:Android iOS Linux macOS Metro SamsungTV Switch Tizen tvOS WebGL Wii Windows
|
unity.platform == 'iOS' |
unity.timeSinceStart |
應(yīng)用程序會話開始以來的時間(以毫秒為單位)谷异。 | unity.timeSinceStart >= 60000 |
unity.graphicsDeviceVendor |
用戶圖形卡的供應(yīng)商。 | unity.graphicsDeviceVendor == 'ATI Technologies Inc.' |
unity.ram |
設(shè)備上的RAM內(nèi)存量锦聊,以MB為單位歹嘹。 | unity.ram >= 16384 |
unity.model |
設(shè)備的型號。 |
unity.model == "LGE Nexus 5" 或者 unity.model.contains("Nexus")
|
還可以使用邏輯表達式來作為表達式:user.score >= 10 && app.level == 5
.
如果想讓此規(guī)則適用于所有用戶, 只需要填寫 true
就可以了.
我們來看幾個例子:
- 根據(jù)應(yīng)用關(guān)卡的 level ,關(guān)卡越高,敵人越多,敵人傷害越高
-
根據(jù)特定節(jié)日來配置規(guī)則
更多關(guān)于配置和規(guī)則的信息: Rules and Settings
還可以使用 REST API
來設(shè)置規(guī)則和配置: REST API
4. 代碼集成
通過上面的學(xué)習,我們知道了如何設(shè)置規(guī)則和配置,那么我們應(yīng)該如何獲取這些規(guī)則和配置呢?
我設(shè)置了三個配置,它們的默認值如下:
再來配置兩條Rule:
Vip_Rule: 對于
app.level>5
的用戶, Money
被修改為 8888
,isVip
被修改為 False
.Score_Rule: 對于
user.score>100
的用戶,Name
被修改為ScoreKing
.配合下面的代碼,我們來看打印結(jié)果.
using UnityEngine;
using Unity.RemoteConfig;
using Newtonsoft.Json;
public class RemoteConfigExample : MonoBehaviour {
public struct userAttributes {
// 這個結(jié)構(gòu)體用來定義用戶畫像相關(guān)的字段,如果不需要,請設(shè)置為一個空的結(jié)構(gòu)體.
// 下面的字段都可以使用 user 配合點語法設(shè)置為 condition.
public int score;
public int age;
}
public struct appAttributes {
// 這個結(jié)構(gòu)體用來定義應(yīng)用相關(guān)的字段,如果不需要,請設(shè)置為一個空的結(jié)構(gòu)體.
// 下面的字段都可以使用 app 配合點語法設(shè)置為 condition.
public int level;
public string appVersion;
}
// 每次請求都會生成一個 assignmentId, 可以用來分析和追蹤請求數(shù)據(jù)
public string assignmentId;
// 這里聲明的就是我們需要遠程動態(tài)配置的字段了.必須設(shè)置合適的默認值
public bool isVip = false;
public int Money = 100;
public string Name = "Default Name";
void Awake () {
// 在這里我們設(shè)置為應(yīng)用啟動的時候去請求遠程配置
// 添加一個回調(diào)
ConfigManager.FetchCompleted += ApplyRemoteSettings;
// 可以設(shè)置自定義的CustomUserID,用來分析和篩選用戶數(shù)據(jù)
ConfigManager.SetCustomUserID("calabash_one");
// 因為存在請求不回來或者回來的時候應(yīng)用已經(jīng)啟動的情況,因此必須要給字段設(shè)置合適的初始值.
// app和user的數(shù)據(jù)初始化后需要存儲在本地,等待下次獲取遠程配置的時候取出使用
userAttributes user = new userAttributes();;
string userStr = PlayerPrefs.GetString("userKey2");
if (string.IsNullOrEmpty(userStr))
{
user.score = 101;
string key = JsonConvert.SerializeObject(user);
PlayerPrefs.SetString("userKey2", key);
}
else
{
user = JsonConvert.DeserializeObject<userAttributes>(userStr);
}
// 這里懶得存了 大家理解意思就好
appAttributes app = new appAttributes();
app.level = 6;
// 使用下面的API來獲取遠程配置
ConfigManager.FetchConfigs<userAttributes, appAttributes>(user, app);
}
// 使用回調(diào)來接收遠程配置的數(shù)據(jù):
void ApplyRemoteSettings (ConfigResponse configResponse) {
switch (configResponse.requestOrigin) {
case ConfigOrigin.Default:
Debug.Log ("No settings loaded this session; 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.");
assignmentId = ConfigManager.appConfig.assignmentID;
isVip = ConfigManager.appConfig.GetBool("isVip");
Money = ConfigManager.appConfig.GetInt("Money");
Name = ConfigManager.appConfig.GetString("Name");
Debug.Log("isVip: " + isVip + "Money: " + Money + "Name: " + Name);
Debug.Log(ConfigManager.appConfig.GetKeys().Length);
break;
}
}
}
打印結(jié)果如下:
isVip: False Money: 8888 Name: ScoreKing
可以看到,通過遠程配置修改了我們本地配置的值.
需要注意的是:
- 關(guān)于
user
和app
兩個結(jié)構(gòu)體的數(shù)據(jù),在初始化的時候需要保存下來,隨著游戲的進程去更新對應(yīng)的字段,比如用戶修改了自己的年齡后,要去更新保存的user
信息,這樣每次遠程配置請求的時候,取出保存的信息,發(fā)送給服務(wù)器,才能使配置的Rules
起到準確的效果;在這里我使用的是Newtonsoft.Json + PlayerPrefs
來進行轉(zhuǎn)換和存儲,也可以通過寫入到文件來讀取. -
user
和app
兩個結(jié)構(gòu)體是可選的,如果沒有需求,保持兩個結(jié)構(gòu)體為空就可以了. - 關(guān)于代碼中使用的類和方法,可以查看這里:Scripting API
5. Assignment reports(摘要報告)
在Dashboard
中可以生成Assignment reports
,有兩種格式,一種是Summary
,另一種是Aggregate
,格式都是csv
.
- Summary可以看到更多的用戶信息.
列名 | 描述 |
---|---|
projectId |
項目的ProjectId ,在文章第一步的時候生產(chǎn),在Dashboard 中可以查看到 |
userId |
由Unity生成的隨機GUID括丁,用于唯一標識使用應(yīng)用程序的用戶(重新安裝后可能會更改),使用的是原始ID的哈希值荞下。 |
customUserId |
開發(fā)人員生成的唯一標識符。使用的是原始ID的哈希值史飞。 |
assignmentId |
用戶發(fā)起遠程配置請求時生成的唯一ID尖昏。 |
ruleId |
分配給用戶的規(guī)則的GUID。 |
ruleName |
分配給用戶的規(guī)則名稱 |
ts |
GMT時間戳构资。 |
- Aggregate可以看到對應(yīng)規(guī)則的人群數(shù)量.
列名 | 描述 |
---|---|
ruleId |
分配給用戶的規(guī)則的GUID抽诉。 |
ruleName |
分配給用戶的規(guī)則名稱 |
unique_user_count |
該規(guī)則下的用戶數(shù)量 |
6. 后續(xù)改進思路
通過上面的學(xué)習和實踐,相信大家已經(jīng)掌握了Unity Remote Config的基本使用,其實在整個流程中可以改進的點很多,我先來拋磚引玉.
- 關(guān)于遠程配置功能的封裝,該模塊其實可以作為基本功能給每個新創(chuàng)建的App使用,因此可以集成到公共的Package中.
- 關(guān)于
user
以及app
兩個結(jié)構(gòu)體應(yīng)該具有擴展性,可以設(shè)置兩個接口供外界返回兩個對應(yīng)的自定義結(jié)構(gòu)體,然后再和默認的結(jié)構(gòu)體數(shù)據(jù)合并后去請求遠程配置. - 關(guān)于配置項可以抽取為一個單獨的Model,方便外界調(diào)用和修改.