iOS接入热云

This commit is contained in:
xiaohui.wang 2022-05-23 10:07:03 +08:00
parent d181e9619e
commit f31a89bfc5
7 changed files with 250 additions and 198 deletions

View File

@ -28,11 +28,11 @@ public class InterVideoButton : JPButton
switch (iVNumber) switch (iVNumber)
{ {
case IVNumber.Inter1: case IVNumber.Inter1:
JoypacAdManager.Instance.ShowInterstitial(null, ConstStringKey.JOYPAC_SDK_INTERID, "test1"); // JoypacAdManager.Instance.ShowInterstitial(null, ConstStringKey.JOYPAC_SDK_INTERID, "test1");
break; break;
case IVNumber.Inter2: case IVNumber.Inter2:
#if TWOINTER #if TWOINTER
JoypacAdManager.Instance.ShowInterstitial(null, ConstStringKey.JOYPAC_SDK_INTERID2,"test2"); // JoypacAdManager.Instance.ShowInterstitial(null, ConstStringKey.JOYPAC_SDK_INTERID2,"test2");
#endif #endif
break; break;
default: default:

View File

@ -68,6 +68,14 @@ public class JoypacStaticBuildPostProcessor
proj.AddFrameworkToProject(target, "AdSupport.framework", false); proj.AddFrameworkToProject(target, "AdSupport.framework", false);
proj.AddFrameworkToProject(target, "CoreMotion.framework", false);
proj.AddFrameworkToProject(target, "iAd.framework", false);
proj.AddFrameworkToProject(target, "AdServices.framework", true);
proj.AddFrameworkToProject(target, "AVFoundation.framework", false);
proj.AddFrameworkToProject(target, "CFNetwork.framework", false);
proj.AddFrameworkToProject(target, "WebKit.framework", false);
// Foundation.framework // Foundation.framework
//UIKit.framework //UIKit.framework
@ -123,6 +131,9 @@ public class JoypacStaticBuildPostProcessor
proj.AddFileToBuild(target, fileGuidSqlite); proj.AddFileToBuild(target, fileGuidSqlite);
proj.AddFrameworkToProject(target, "AppTrackingTransparency.framework", true);//这里要check一下 proj.AddFrameworkToProject(target, "AppTrackingTransparency.framework", true);//这里要check一下
proj.AddFileToBuild(target, fileGuidSqlite);
fileGuidSqlite = proj.AddFile("usr/lib/libresolv.9.tbd", "Libraries/libresolv.9.tbd", PBXSourceTree.Sdk);
//--------------------------------------在JoyPacSDK中加入 ------------------------------------------------------------------------- //--------------------------------------在JoyPacSDK中加入 -------------------------------------------------------------------------
//#if UNITY_2019_3_OR_NEWER//这个路径要改一下不用bundle用对应的文件夹但是需要check是否存在不存在就报个错。 //#if UNITY_2019_3_OR_NEWER//这个路径要改一下不用bundle用对应的文件夹但是需要check是否存在不存在就报个错。
@ -216,6 +227,10 @@ public class JoypacStaticBuildPostProcessor
plist.root.SetString("BytePlusAppId", "353656"); plist.root.SetString("BytePlusAppId", "353656");
plist.root.SetBoolean("isChina", true); plist.root.SetBoolean("isChina", true);
plist.root.SetString("reyunAppKey", "0ab788eb8072e0c4a6117ea3faf20c9c");
plist.root.SetString("projectAppID", "10007");
plist.root.SetString("KlevinApplicationIdentifier", ""); plist.root.SetString("KlevinApplicationIdentifier", "");
File.WriteAllText(plistPath, plist.WriteToString()); File.WriteAllText(plistPath, plist.WriteToString());

View File

@ -119,7 +119,14 @@ public class JoypacAdClient : MonoBehaviour
[DllImport("__Internal")] [DllImport("__Internal")]
private static extern void profileSet(string profileParams); private static extern void profileSet(string profileParams);
// 热云数据埋点上传
[DllImport("__Internal")]
private static extern void reyunEvent(string eventId, string eventParams);
public void ReyunEvent(string eventId, string eventParams)
{
reyunEvent(eventId, eventParams);
}
//Finder相关 //Finder相关
public void UploadEvent(string eventId, string eventParams) public void UploadEvent(string eventId, string eventParams)
{ {
@ -430,6 +437,12 @@ public class JoypacAdClient : MonoBehaviour
Debug.Log("finder 插屏展示准备"); Debug.Log("finder 插屏展示准备");
JoypacAnalyticsManager.Instance.aPPAdsShowCome = PlayerPrefs.GetString(StaticStringsEvent.aPPAdsShowCome, StaticStringsEvent.Interstitial);
JoypacAnalyticsManager.Instance.aPPAdsShowAdType = PlayerPrefs.GetString(StaticStringsEvent.aPPAdsShowAdType, StaticStringsEvent.Interstitial);
JoypacAnalyticsManager.Instance.APPAdsShow(jsonTemp); JoypacAnalyticsManager.Instance.APPAdsShow(jsonTemp);
Debug.Log("finder 插屏展示结束"); Debug.Log("finder 插屏展示结束");
@ -530,6 +543,9 @@ public class JoypacAdClient : MonoBehaviour
Dictionary<string, object> jsonTemp = new Dictionary<string, object>(); Dictionary<string, object> jsonTemp = new Dictionary<string, object>();
jsonTemp = JsonMapper.ToObject<Dictionary<string, object>>(json); jsonTemp = JsonMapper.ToObject<Dictionary<string, object>>(json);
JoypacAnalyticsManager.Instance.aPPAdsShowCome = PlayerPrefs.GetString(StaticStringsEvent.aPPAdsShowCome, StaticStringsEvent.Reward);
JoypacAnalyticsManager.Instance.aPPAdsShowAdType = PlayerPrefs.GetString(StaticStringsEvent.aPPAdsShowAdType, StaticStringsEvent.Reward);
JoypacAnalyticsManager.Instance.APPAdsShow(jsonTemp); JoypacAnalyticsManager.Instance.APPAdsShow(jsonTemp);
Debug.Log("finder 激励视频展示结束"); Debug.Log("finder 激励视频展示结束");

View File

@ -122,5 +122,10 @@
public const string Recipe2Reward = "Recipe2Reward"; public const string Recipe2Reward = "Recipe2Reward";
public const string aPPAdsShowCome = "aPPAdsShowCome";
public const string aPPAdsShowAdType = "aPPAdsShowAdType";
} }

View File

@ -89,6 +89,9 @@ public class JoypacAnalyticsManager : MonoBehaviour
aPPAdsShowCome = AdsShowCome; aPPAdsShowCome = AdsShowCome;
aPPAdsShowAdType = AdsShowAdType; aPPAdsShowAdType = AdsShowAdType;
PlayerPrefs.SetString(StaticStringsEvent.aPPAdsShowCome, AdsShowCome);
PlayerPrefs.SetString(StaticStringsEvent.aPPAdsShowAdType, AdsShowAdType);
// AppFunShow(name,extras); // AppFunShow(name,extras);
AppFunClick(name, from); AppFunClick(name, from);
} }
@ -113,9 +116,9 @@ public class JoypacAnalyticsManager : MonoBehaviour
public void setEvent(string eventName, Dictionary<string, object> values) public void setEvent(string eventName, Dictionary<string, object> values)
{ {
#if UNITY_ANDROID && !UNITY_EDITOR
Debug.Log("setEvent========coming"); Debug.Log("setEvent========coming");
//ryattrs //ryattrs
#if UNITY_ANDROID && !UNITY_EDITOR
values.Add("ryattrs", JsonConvert.SerializeObject(values)); values.Add("ryattrs", JsonConvert.SerializeObject(values));
JoyPacCurrentcyAdSingle currAdSingleTemp = new JoyPacCurrentcyAdSingle(); JoyPacCurrentcyAdSingle currAdSingleTemp = new JoyPacCurrentcyAdSingle();
@ -143,6 +146,11 @@ public class JoypacAnalyticsManager : MonoBehaviour
currAdSingleTemp.reyunKeyEvent(eventName, JsonConvert.SerializeObject(values)); currAdSingleTemp.reyunKeyEvent(eventName, JsonConvert.SerializeObject(values));
#endif #endif
#if UNITY_IOS && !UNITY_EDITOR
JoypacAdClient.Instance.ReyunEvent(eventName, JsonConvert.SerializeObject(values));
#endif
} }
public void Volcano(VolcanoReYunJson json) public void Volcano(VolcanoReYunJson json)
{ {
@ -246,6 +254,10 @@ public class JoypacAnalyticsManager : MonoBehaviour
currAdSingleTemp.reyun_report_ad_show(aPPAdsShowCome, aPPAdsShowAdType, adSource["AdSourceId"].ToString(), adSource["From"].ToString(), adSource["price_int"].ToString(), adSource["price_string"].ToString(), adSource["currency"].ToString()); currAdSingleTemp.reyun_report_ad_show(aPPAdsShowCome, aPPAdsShowAdType, adSource["AdSourceId"].ToString(), adSource["From"].ToString(), adSource["price_int"].ToString(), adSource["price_string"].ToString(), adSource["currency"].ToString());
// ReYun(temp); // ReYun(temp);
#endif #endif
#if JOYPAC_ReYun && UNITY_IOS&&!UNITY_EDITOR
ReYun(temp);
#endif
} }
public void APPAdsClick(Dictionary<string, object> adSource) public void APPAdsClick(Dictionary<string, object> adSource)
{ {
@ -272,6 +284,10 @@ public class JoypacAnalyticsManager : MonoBehaviour
currAdSingleTemp.reyun_report_ad_click(aPPAdsShowCome, aPPAdsShowAdType, adSource["AdSourceId"].ToString(), adSource["From"].ToString()); currAdSingleTemp.reyun_report_ad_click(aPPAdsShowCome, aPPAdsShowAdType, adSource["AdSourceId"].ToString(), adSource["From"].ToString());
// ReYun(temp); // ReYun(temp);
#endif #endif
#if JOYPAC_ReYun && UNITY_IOS && !UNITY_EDITOR
ReYun(temp);
#endif
} }
public void AppAdsReward(Dictionary<string, object> adSource) public void AppAdsReward(Dictionary<string, object> adSource)
{ {

388
popcorn/Assets/Joypac/Scripts/Thirdparty/ReYunSDK/Traking.cs vendored Executable file → Normal file
View File

@ -1,240 +1,240 @@
using UnityEngine; //using UnityEngine;
//using UnityEngine.UI; ////using UnityEngine.UI;
using System.Collections; //using System.Collections;
using System.Runtime.InteropServices; //using System.Runtime.InteropServices;
using System.Collections.Generic; //using System.Collections.Generic;
public class Tracking: MonoBehaviour //public class Tracking: MonoBehaviour
{ //{
private static Tracking _instance = null; // private static Tracking _instance = null;
public static Tracking Instance { // public static Tracking Instance {
get { // get {
if (!_instance) { // if (!_instance) {
_instance = GameObject.FindObjectOfType (typeof(Tracking)) as Tracking; // _instance = GameObject.FindObjectOfType (typeof(Tracking)) as Tracking;
if (!_instance) { // if (!_instance) {
GameObject am = new GameObject ("Tracking"); // GameObject am = new GameObject ("Tracking");
_instance = am.AddComponent (typeof(Tracking)) as Tracking; // _instance = am.AddComponent (typeof(Tracking)) as Tracking;
} // }
} // }
return _instance; // return _instance;
} // }
} // }
void Awake () // void Awake ()
{ // {
DontDestroyOnLoad (this); // DontDestroyOnLoad (this);
} // }
#if UNITY_IOS // #if UNITY_IOS
[DllImport ("__Internal")] // [DllImport ("__Internal")]
private static extern void _internalInitWithAppKeyAndChannel_Tracking (string appKey, string channelId); // private static extern void _internalInitWithAppKeyAndChannel_Tracking (string appKey, string channelId);
[DllImport ("__Internal")] // [DllImport ("__Internal")]
private static extern void _internalSetRegisterWithAccountID_Tracking (string account); // private static extern void _internalSetRegisterWithAccountID_Tracking (string account);
[DllImport ("__Internal")] // [DllImport ("__Internal")]
private static extern void _internalSetLoginWithAccountID_Tracking (string account); // private static extern void _internalSetLoginWithAccountID_Tracking (string account);
[DllImport ("__Internal")] // [DllImport ("__Internal")]
private static extern void _internalSetRyzfStart_Tracking (string ryTID, string ryzfType, string hbType, float hbAmount); // private static extern void _internalSetRyzfStart_Tracking (string ryTID, string ryzfType, string hbType, float hbAmount);
[DllImport ("__Internal")] // [DllImport ("__Internal")]
private static extern void _internalSetRyzf_Tracking (string ryTID, string ryzfType, string hbType, float hbAmount); // private static extern void _internalSetRyzf_Tracking (string ryTID, string ryzfType, string hbType, float hbAmount);
[DllImport ("__Internal")] // [DllImport ("__Internal")]
private static extern void _internalSetDD_Tracking (string ryTID, string hbType, float hbAmount); // private static extern void _internalSetDD_Tracking (string ryTID, string hbType, float hbAmount);
[DllImport ("__Internal")] // [DllImport ("__Internal")]
private static extern void _internalSetEvent_Tracking (string EventName); // private static extern void _internalSetEvent_Tracking (string EventName);
[DllImport ("__Internal")] // [DllImport ("__Internal")]
private static extern string _internalGetDeviceId_Tracking (); // private static extern string _internalGetDeviceId_Tracking ();
[DllImport ("__Internal")] // [DllImport ("__Internal")]
private static extern void _internalSetPrintLog_Tracking (bool print); // private static extern void _internalSetPrintLog_Tracking (bool print);
#endif // #endif
#if UNITY_ANDROID // #if UNITY_ANDROID
public static AndroidJavaObject getApplicationContext () // public static AndroidJavaObject getApplicationContext ()
{ // {
using (AndroidJavaClass jc = new AndroidJavaClass ("com.unity3d.player.UnityPlayer")) { // using (AndroidJavaClass jc = new AndroidJavaClass ("com.unity3d.player.UnityPlayer")) {
using (AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject> ("currentActivity")) { // using (AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject> ("currentActivity")) {
return jo.Call<AndroidJavaObject> ("getApplicationContext"); // return jo.Call<AndroidJavaObject> ("getApplicationContext");
} // }
} // }
return null; // return null;
} // }
#endif // #endif
/// <summary> // /// <summary>
/// 初始化方法 // /// 初始化方法
/// </summary> // /// </summary>
/// <param name="appId">appKey</param> // /// <param name="appId">appKey</param>
/// <param name="channelId">标识推广渠道的字符</param> // /// <param name="channelId">标识推广渠道的字符</param>
public void init (string appKey, string channelId) // public void init (string appKey, string channelId)
{ // {
#if UNITY_IOS // #if UNITY_IOS
_internalInitWithAppKeyAndChannel_Tracking (appKey, channelId); // _internalInitWithAppKeyAndChannel_Tracking (appKey, channelId);
#endif // #endif
#if UNITY_ANDROID // #if UNITY_ANDROID
using (AndroidJavaClass TrackingIO = new AndroidJavaClass ("com.reyun.tracking.sdk.Tracking")) { // using (AndroidJavaClass TrackingIO = new AndroidJavaClass ("com.reyun.tracking.sdk.Tracking")) {
TrackingIO.CallStatic ("initWithKeyAndChannelId", getApplicationContext (), appKey, channelId); // TrackingIO.CallStatic ("initWithKeyAndChannelId", getApplicationContext (), appKey, channelId);
} // }
#endif // #endif
} // }
/// <summary> // /// <summary>
/// 玩家服务器注册 // /// 玩家服务器注册
/// </summary> // /// </summary>
/// <param name="account">账号ID</param> // /// <param name="account">账号ID</param>
/// // ///
public void register (string account) // public void register (string account)
{ // {
#if UNITY_IOS // #if UNITY_IOS
_internalSetRegisterWithAccountID_Tracking (account); // _internalSetRegisterWithAccountID_Tracking (account);
#endif // #endif
#if UNITY_ANDROID // #if UNITY_ANDROID
using (AndroidJavaClass TrackingIO = new AndroidJavaClass ("com.reyun.tracking.sdk.Tracking")) { // using (AndroidJavaClass TrackingIO = new AndroidJavaClass ("com.reyun.tracking.sdk.Tracking")) {
TrackingIO.CallStatic ("setRegisterWithAccountID", account); // TrackingIO.CallStatic ("setRegisterWithAccountID", account);
} // }
#endif // #endif
} // }
/// <summary> // /// <summary>
/// 玩家的账号登陆服务器 // /// 玩家的账号登陆服务器
/// </summary> // /// </summary>
/// <param name="account">账号</param> // /// <param name="account">账号</param>
public void login (string account) // public void login (string account)
{ // {
#if UNITY_IOS // #if UNITY_IOS
_internalSetLoginWithAccountID_Tracking (account); // _internalSetLoginWithAccountID_Tracking (account);
#endif // #endif
#if UNITY_ANDROID // #if UNITY_ANDROID
using (AndroidJavaClass TrackingIO = new AndroidJavaClass ("com.reyun.tracking.sdk.Tracking")) { // using (AndroidJavaClass TrackingIO = new AndroidJavaClass ("com.reyun.tracking.sdk.Tracking")) {
TrackingIO.CallStatic ("setLoginSuccessBusiness", account); // TrackingIO.CallStatic ("setLoginSuccessBusiness", account);
} // }
#endif // #endif
} // }
/// <summary> // /// <summary>
/// 玩家开始充值数据 // /// 玩家开始充值数据
/// </summary> // /// </summary>
/// <param name="transactionId">交易的流水号</param> // /// <param name="transactionId">交易的流水号</param>
/// <param name="paymentType">支付类型</param> // /// <param name="paymentType">支付类型</param>
/// <param name="currencyType">货币类型</param> // /// <param name="currencyType">货币类型</param>
/// <param name="currencyAmount">支付的真实货币的金额</param> // /// <param name="currencyAmount">支付的真实货币的金额</param>
public void setryzfStart (string ryTID, string ryzfType, string hbType, float hbAmount) // public void setryzfStart (string ryTID, string ryzfType, string hbType, float hbAmount)
{ // {
#if UNITY_IOS // #if UNITY_IOS
_internalSetRyzfStart_Tracking (ryTID, ryzfType, hbType, hbAmount); // _internalSetRyzfStart_Tracking (ryTID, ryzfType, hbType, hbAmount);
#endif // #endif
#if UNITY_ANDROID // #if UNITY_ANDROID
using (AndroidJavaClass TrackingIO = new AndroidJavaClass ("com.reyun.tracking.sdk.Tracking")) { // using (AndroidJavaClass TrackingIO = new AndroidJavaClass ("com.reyun.tracking.sdk.Tracking")) {
TrackingIO.CallStatic ("setPaymentStart", ryTID, ryzfType, hbType, hbAmount); // TrackingIO.CallStatic ("setPaymentStart", ryTID, ryzfType, hbType, hbAmount);
} // }
#endif // #endif
} // }
/// <summary> // /// <summary>
/// 玩家的充值数据 // /// 玩家的充值数据
/// </summary> // /// </summary>
/// <param name="transactionId">交易的流水号</param> // /// <param name="transactionId">交易的流水号</param>
/// <param name="paymentType">支付类型</param> // /// <param name="paymentType">支付类型</param>
/// <param name="currencyType">货币类型</param> // /// <param name="currencyType">货币类型</param>
/// <param name="currencyAmount">支付的真实货币的金额</param> // /// <param name="currencyAmount">支付的真实货币的金额</param>
public void setryzf (string ryTID, string ryzfType, string hbType, float hbAmount) // public void setryzf (string ryTID, string ryzfType, string hbType, float hbAmount)
{ // {
#if UNITY_IOS // #if UNITY_IOS
_internalSetRyzf_Tracking (ryTID, ryzfType, hbType, hbAmount); // _internalSetRyzf_Tracking (ryTID, ryzfType, hbType, hbAmount);
#endif // #endif
#if UNITY_ANDROID // #if UNITY_ANDROID
using (AndroidJavaClass TrackingIO = new AndroidJavaClass ("com.reyun.tracking.sdk.Tracking")) { // using (AndroidJavaClass TrackingIO = new AndroidJavaClass ("com.reyun.tracking.sdk.Tracking")) {
TrackingIO.CallStatic ("setPayment", ryTID, ryzfType, hbType, hbAmount); // TrackingIO.CallStatic ("setPayment", ryTID, ryzfType, hbType, hbAmount);
} // }
#endif // #endif
} // }
public void setDD (string ryTID, string hbType, float hbAmount) // public void setDD (string ryTID, string hbType, float hbAmount)
{ // {
#if UNITY_IOS // #if UNITY_IOS
_internalSetDD_Tracking (ryTID,hbType,hbAmount); // _internalSetDD_Tracking (ryTID,hbType,hbAmount);
#endif // #endif
#if UNITY_ANDROID // #if UNITY_ANDROID
using (AndroidJavaClass TrackingIO = new AndroidJavaClass ("com.reyun.tracking.sdk.Tracking")) { // using (AndroidJavaClass TrackingIO = new AndroidJavaClass ("com.reyun.tracking.sdk.Tracking")) {
TrackingIO.CallStatic ("setOrder", ryTID, hbType, hbAmount); // TrackingIO.CallStatic ("setOrder", ryTID, hbType, hbAmount);
} // }
#endif // #endif
} // }
/// <summary> // /// <summary>
/// 统计玩家的自定义事件 // /// 统计玩家的自定义事件
/// </summary> // /// </summary>
/// <param name="eventName">事件名</param> // /// <param name="eventName">事件名</param>
public void setEvent (string eventName) // public void setEvent (string eventName)
{ // {
#if UNITY_IOS // #if UNITY_IOS
_internalSetEvent_Tracking (eventName); // _internalSetEvent_Tracking (eventName);
#endif // #endif
#if UNITY_ANDROID // #if UNITY_ANDROID
using (AndroidJavaClass reyun = new AndroidJavaClass ("com.reyun.tracking.sdk.Tracking")) { // using (AndroidJavaClass reyun = new AndroidJavaClass ("com.reyun.tracking.sdk.Tracking")) {
reyun.CallStatic ("setEvent", eventName, null); // reyun.CallStatic ("setEvent", eventName, null);
} // }
#endif // #endif
} // }
/// <summary> // /// <summary>
/// 获取用户的设备ID信息 // /// 获取用户的设备ID信息
/// </summary> // /// </summary>
public string getDeviceId () // public string getDeviceId ()
{ // {
#if UNITY_IOS // #if UNITY_IOS
return _internalGetDeviceId_Tracking (); // return _internalGetDeviceId_Tracking ();
#endif // #endif
#if UNITY_ANDROID // #if UNITY_ANDROID
string str = "unknown"; // string str = "unknown";
using (AndroidJavaClass TrackingIO = new AndroidJavaClass ("com.reyun.tracking.sdk.Tracking")) { // using (AndroidJavaClass TrackingIO = new AndroidJavaClass ("com.reyun.tracking.sdk.Tracking")) {
str = TrackingIO.CallStatic<string> ("getDeviceId"); // str = TrackingIO.CallStatic<string> ("getDeviceId");
} // }
return str; // return str;
#endif // #endif
return "unknown"; // return "unknown";
} // }
/// 开启日志打印 // /// 开启日志打印
public void setPrintLog (bool print) // public void setPrintLog (bool print)
{ // {
#if UNITY_IOS //#if UNITY_IOS
_internalSetPrintLog_Tracking (print); // _internalSetPrintLog_Tracking (print);
#endif //#endif
#if UNITY_ANDROID // #if UNITY_ANDROID
using (AndroidJavaClass reyunConst = new AndroidJavaClass ("com.reyun.tracking.common.ReYunConst")) { // using (AndroidJavaClass reyunConst = new AndroidJavaClass ("com.reyun.tracking.common.ReYunConst")) {
reyunConst.SetStatic <bool> ("DebugMode", print); // reyunConst.SetStatic <bool> ("DebugMode", print);
} // }
#endif // #endif
} // }
} //}

View File

@ -751,7 +751,7 @@ PlayerSettings:
webGLWasmStreaming: 0 webGLWasmStreaming: 0
scriptingDefineSymbols: scriptingDefineSymbols:
1: TextMeshPro 1: TextMeshPro
4: TextMeshPro;Notifications;IssuePerson;JOYPAC_Volcano_OS 4: TextMeshPro;Notifications;IssuePerson;JOYPAC_Volcano_OS;JOYPAC_ReYun
7: ANDROID_CN;TextMeshPro;JOYPAC_ReYun;JOYPAC_Volcano 7: ANDROID_CN;TextMeshPro;JOYPAC_ReYun;JOYPAC_Volcano
13: TextMeshPro 13: TextMeshPro
14: TextMeshPro 14: TextMeshPro