IAPDemo.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831
  1. //#if UNITY_ANDROID || UNITY_IPHONE || UNITY_STANDALONE_OSX || UNITY_TVOS
  2. //// You must obfuscate your secrets using Window > Unity IAP > Receipt Validation Obfuscator
  3. //// before receipt validation will compile in this sample.
  4. //// #define RECEIPT_VALIDATION
  5. //#endif
  6. ////#define DELAY_CONFIRMATION // Returns PurchaseProcessingResult.Pending from ProcessPurchase, then calls ConfirmPendingPurchase after a delay
  7. ////#define USE_PAYOUTS // Enables use of PayoutDefinitions to specify what the player should receive when a product is purchased
  8. //using System;
  9. //using System.Collections;
  10. //using System.Collections.Generic;
  11. //using UnityEngine;
  12. //using UnityEngine.Purchasing;
  13. //using UnityEngine.Store; // UnityChannel
  14. //using UnityEngine.UI;
  15. //#if RECEIPT_VALIDATION
  16. //using UnityEngine.Purchasing.Security;
  17. //#endif
  18. ///// <summary>
  19. ///// An example of Unity IAP functionality.
  20. ///// To use with your account, configure the product ids (AddProduct).
  21. ///// </summary>
  22. //[AddComponentMenu("Unity IAP/Demo")]
  23. //public class IAPDemo : MonoBehaviour, IStoreListener
  24. //{
  25. // // Unity IAP objects
  26. // private IStoreController m_Controller;
  27. // private IAppleExtensions m_AppleExtensions;
  28. // private IMoolahExtension m_MoolahExtensions;
  29. // private ISamsungAppsExtensions m_SamsungExtensions;
  30. // private IMicrosoftExtensions m_MicrosoftExtensions;
  31. // private IUnityChannelExtensions m_UnityChannelExtensions;
  32. // #pragma warning disable 0414
  33. // private bool m_IsGooglePlayStoreSelected;
  34. // #pragma warning restore 0414
  35. // private bool m_IsSamsungAppsStoreSelected;
  36. // private bool m_IsCloudMoolahStoreSelected;
  37. // private bool m_IsUnityChannelSelected;
  38. // private string m_LastTransationID;
  39. // private string m_LastReceipt;
  40. // private string m_CloudMoolahUserName;
  41. // private bool m_IsLoggedIn = false;
  42. // private UnityChannelLoginHandler unityChannelLoginHandler; // Helper for interfacing with UnityChannel API
  43. // private bool m_FetchReceiptPayloadOnPurchase = false;
  44. // private int m_SelectedItemIndex = -1; // -1 == no product
  45. // private bool m_PurchaseInProgress;
  46. // private Selectable m_InteractableSelectable; // Optimization used for UI state management
  47. // #if RECEIPT_VALIDATION
  48. // private CrossPlatformValidator validator;
  49. // #endif
  50. // /// <summary>
  51. // /// This will be called when Unity IAP has finished initialising.
  52. // /// </summary>
  53. // public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
  54. // {
  55. // m_Controller = controller;
  56. // m_AppleExtensions = extensions.GetExtension<IAppleExtensions> ();
  57. // m_SamsungExtensions = extensions.GetExtension<ISamsungAppsExtensions> ();
  58. // m_MoolahExtensions = extensions.GetExtension<IMoolahExtension> ();
  59. // m_MicrosoftExtensions = extensions.GetExtension<IMicrosoftExtensions> ();
  60. // m_UnityChannelExtensions = extensions.GetExtension<IUnityChannelExtensions> ();
  61. // InitUI(controller.products.all);
  62. // // On Apple platforms we need to handle deferred purchases caused by Apple's Ask to Buy feature.
  63. // // On non-Apple platforms this will have no effect; OnDeferred will never be called.
  64. // m_AppleExtensions.RegisterPurchaseDeferredListener(OnDeferred);
  65. // Debug.Log("Available items:");
  66. // foreach (var item in controller.products.all)
  67. // {
  68. // if (item.availableToPurchase)
  69. // {
  70. // Debug.Log(string.Join(" - ",
  71. // new[]
  72. // {
  73. // item.metadata.localizedTitle,
  74. // item.metadata.localizedDescription,
  75. // item.metadata.isoCurrencyCode,
  76. // item.metadata.localizedPrice.ToString(),
  77. // item.metadata.localizedPriceString,
  78. // item.transactionID,
  79. // item.receipt
  80. // }));
  81. // }
  82. // }
  83. // // Prepare model for purchasing
  84. // if (m_Controller.products.all.Length > 0)
  85. // {
  86. // m_SelectedItemIndex = 0;
  87. // }
  88. // // Populate the product menu now that we have Products
  89. // for (int t = 0; t < m_Controller.products.all.Length; t++)
  90. // {
  91. // var item = m_Controller.products.all[t];
  92. // var description = string.Format("{0} | {1} => {2}", item.metadata.localizedTitle, item.metadata.localizedPriceString, item.metadata.localizedPrice);
  93. // // NOTE: my options list is created in InitUI
  94. // GetDropdown().options[t] = new Dropdown.OptionData(description);
  95. // }
  96. // // Ensure I render the selected list element
  97. // GetDropdown().RefreshShownValue();
  98. // // Now that I have real products, begin showing product purchase history
  99. // UpdateHistoryUI();
  100. // LogProductDefinitions();
  101. // }
  102. // /// <summary>
  103. // /// This will be called when a purchase completes.
  104. // /// </summary>
  105. // public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs e)
  106. // {
  107. // Debug.Log("Purchase OK: " + e.purchasedProduct.definition.id);
  108. // Debug.Log("Receipt: " + e.purchasedProduct.receipt);
  109. // m_LastTransationID = e.purchasedProduct.transactionID;
  110. // m_LastReceipt = e.purchasedProduct.receipt;
  111. // m_PurchaseInProgress = false;
  112. // // Decode the UnityChannelPurchaseReceipt, extracting the gameOrderId
  113. // if (m_IsUnityChannelSelected)
  114. // {
  115. // var unifiedReceipt = JsonUtility.FromJson<UnifiedReceipt>(e.purchasedProduct.receipt);
  116. // if (unifiedReceipt != null && !string.IsNullOrEmpty(unifiedReceipt.Payload))
  117. // {
  118. // var purchaseReceipt = JsonUtility.FromJson<UnityChannelPurchaseReceipt>(unifiedReceipt.Payload);
  119. // Debug.LogFormat("UnityChannel receipt: storeSpecificId = {0}, transactionId = {1}, orderQueryToken = {2}",
  120. // purchaseReceipt.storeSpecificId, purchaseReceipt.transactionId, purchaseReceipt.orderQueryToken);
  121. // }
  122. // }
  123. // #if RECEIPT_VALIDATION
  124. // // Local validation is available for GooglePlay, Apple, and UnityChannel stores
  125. // if (m_IsGooglePlayStoreSelected ||
  126. // (m_IsUnityChannelSelected && m_FetchReceiptPayloadOnPurchase) ||
  127. // Application.platform == RuntimePlatform.IPhonePlayer ||
  128. // Application.platform == RuntimePlatform.OSXPlayer ||
  129. // Application.platform == RuntimePlatform.tvOS) {
  130. // try {
  131. // var result = validator.Validate(e.purchasedProduct.receipt);
  132. // Debug.Log("Receipt is valid. Contents:");
  133. // foreach (IPurchaseReceipt productReceipt in result) {
  134. // Debug.Log(productReceipt.productID);
  135. // Debug.Log(productReceipt.purchaseDate);
  136. // Debug.Log(productReceipt.transactionID);
  137. // GooglePlayReceipt google = productReceipt as GooglePlayReceipt;
  138. // if (null != google) {
  139. // Debug.Log(google.purchaseState);
  140. // Debug.Log(google.purchaseToken);
  141. // }
  142. // UnityChannelReceipt unityChannel = productReceipt as UnityChannelReceipt;
  143. // if (null != unityChannel) {
  144. // Debug.Log(unityChannel.productID);
  145. // Debug.Log(unityChannel.purchaseDate);
  146. // Debug.Log(unityChannel.transactionID);
  147. // }
  148. // AppleInAppPurchaseReceipt apple = productReceipt as AppleInAppPurchaseReceipt;
  149. // if (null != apple) {
  150. // Debug.Log(apple.originalTransactionIdentifier);
  151. // Debug.Log(apple.subscriptionExpirationDate);
  152. // Debug.Log(apple.cancellationDate);
  153. // Debug.Log(apple.quantity);
  154. // }
  155. // // For improved security, consider comparing the signed
  156. // // IPurchaseReceipt.productId, IPurchaseReceipt.transactionID, and other data
  157. // // embedded in the signed receipt objects to the data which the game is using
  158. // // to make this purchase.
  159. // }
  160. // } catch (IAPSecurityException ex) {
  161. // Debug.Log("Invalid receipt, not unlocking content. " + ex);
  162. // return PurchaseProcessingResult.Complete;
  163. // }
  164. // }
  165. // #endif
  166. // // Unlock content from purchases here.
  167. //#if USE_PAYOUTS
  168. // if (e.purchasedProduct.definition.payouts != null) {
  169. // Debug.Log("Purchase complete, paying out based on defined payouts");
  170. // foreach (var payout in e.purchasedProduct.definition.payouts) {
  171. // Debug.Log(string.Format("Granting {0} {1} {2} {3}", payout.quantity, payout.typeString, payout.subtype, payout.data));
  172. // }
  173. // }
  174. //#endif
  175. // // Indicate if we have handled this purchase.
  176. // // PurchaseProcessingResult.Complete: ProcessPurchase will not be called
  177. // // with this product again, until next purchase.
  178. // // PurchaseProcessingResult.Pending: ProcessPurchase will be called
  179. // // again with this product at next app launch. Later, call
  180. // // m_Controller.ConfirmPendingPurchase(Product) to complete handling
  181. // // this purchase. Use to transactionally save purchases to a cloud
  182. // // game service.
  183. //#if DELAY_CONFIRMATION
  184. // StartCoroutine(ConfirmPendingPurchaseAfterDelay(e.purchasedProduct));
  185. // return PurchaseProcessingResult.Pending;
  186. //#else
  187. // UpdateHistoryUI();
  188. // return PurchaseProcessingResult.Complete;
  189. //#endif
  190. // }
  191. //#if DELAY_CONFIRMATION
  192. // private HashSet<string> m_PendingProducts = new HashSet<string>();
  193. // private IEnumerator ConfirmPendingPurchaseAfterDelay(Product p)
  194. // {
  195. // m_PendingProducts.Add(p.definition.id);
  196. // Debug.Log("Delaying confirmation of " + p.definition.id + " for 5 seconds.");
  197. // UpdateHistoryUI();
  198. // yield return new WaitForSeconds(5f);
  199. // Debug.Log("Confirming purchase of " + p.definition.id);
  200. // m_Controller.ConfirmPendingPurchase(p);
  201. // m_PendingProducts.Remove(p.definition.id);
  202. // UpdateHistoryUI();
  203. // }
  204. //#endif
  205. // /// <summary>
  206. // /// This will be called is an attempted purchase fails.
  207. // /// </summary>
  208. // public void OnPurchaseFailed(Product item, PurchaseFailureReason r)
  209. // {
  210. // Debug.Log("Purchase failed: " + item.definition.id);
  211. // Debug.Log(r);
  212. // if (m_IsUnityChannelSelected)
  213. // {
  214. // var extra = m_UnityChannelExtensions.GetLastPurchaseError();
  215. // var purchaseError = JsonUtility.FromJson<UnityChannelPurchaseError>(extra);
  216. // if (purchaseError != null && purchaseError.purchaseInfo != null)
  217. // {
  218. // // Additional information about purchase failure.
  219. // var purchaseInfo = purchaseError.purchaseInfo;
  220. // Debug.LogFormat("UnityChannel purchaseInfo: productCode = {0}, gameOrderId = {1}, orderQueryToken = {2}",
  221. // purchaseInfo.productCode, purchaseInfo.gameOrderId, purchaseInfo.orderQueryToken);
  222. // }
  223. // // Determine if the user already owns this item and that it can be added to
  224. // // their inventory, if not already present.
  225. //#if UNITY_5_6_OR_NEWER
  226. // if (r == PurchaseFailureReason.DuplicateTransaction)
  227. // {
  228. // // Unlock `item` in inventory if not already present.
  229. // Debug.Log("Duplicate transaction detected, unlock this item");
  230. // }
  231. //#else // Building using Unity strictly less than 5.6; e.g 5.3-5.5.
  232. // // In Unity 5.3 the enum PurchaseFailureReason.DuplicateTransaction
  233. // // may not be available (is available in 5.6 ... specifically
  234. // // 5.5.1p1+, 5.4.4p2+) and can be substituted with this call.
  235. // if (r == PurchaseFailureReason.Unknown)
  236. // {
  237. // if (purchaseError != null && purchaseError.error != null && purchaseError.error.Equals("DuplicateTransaction"))
  238. // {
  239. // // Unlock `item` in inventory if not already present.
  240. // Debug.Log("Duplicate transaction detected, unlock this item");
  241. // }
  242. // }
  243. //#endif
  244. // }
  245. // m_PurchaseInProgress = false;
  246. // }
  247. // public void OnInitializeFailed(InitializationFailureReason error)
  248. // {
  249. // Debug.Log("Billing failed to initialize!");
  250. // switch (error)
  251. // {
  252. // case InitializationFailureReason.AppNotKnown:
  253. // Debug.LogError("Is your App correctly uploaded on the relevant publisher console?");
  254. // break;
  255. // case InitializationFailureReason.PurchasingUnavailable:
  256. // // Ask the user if billing is disabled in device settings.
  257. // Debug.Log("Billing disabled!");
  258. // break;
  259. // case InitializationFailureReason.NoProductsAvailable:
  260. // // Developer configuration error; check product metadata.
  261. // Debug.Log("No products available for purchase!");
  262. // break;
  263. // }
  264. // }
  265. // [Serializable]
  266. // public class UnityChannelPurchaseError
  267. // {
  268. // public string error;
  269. // public UnityChannelPurchaseInfo purchaseInfo;
  270. // }
  271. // [Serializable]
  272. // public class UnityChannelPurchaseInfo
  273. // {
  274. // public string productCode; // Corresponds to storeSpecificId
  275. // public string gameOrderId; // Corresponds to transactionId
  276. // public string orderQueryToken;
  277. // }
  278. // public void Awake()
  279. // {
  280. // var module = StandardPurchasingModule.Instance();
  281. // // The FakeStore supports: no-ui (always succeeding), basic ui (purchase pass/fail), and
  282. // // developer ui (initialization, purchase, failure code setting). These correspond to
  283. // // the FakeStoreUIMode Enum values passed into StandardPurchasingModule.useFakeStoreUIMode.
  284. // module.useFakeStoreUIMode = FakeStoreUIMode.StandardUser;
  285. // var builder = ConfigurationBuilder.Instance(module);
  286. // // This enables the Microsoft IAP simulator for local testing.
  287. // // You would remove this before building your release package.
  288. // builder.Configure<IMicrosoftConfiguration>().useMockBillingSystem = true;
  289. // m_IsGooglePlayStoreSelected = Application.platform == RuntimePlatform.Android && module.appStore == AppStore.GooglePlay;
  290. // // CloudMoolah Configuration setings
  291. // // All games must set the configuration. the configuration need to apply on the CloudMoolah Portal.
  292. // // CloudMoolah APP Key
  293. // builder.Configure<IMoolahConfiguration>().appKey = "d93f4564c41d463ed3d3cd207594ee1b";
  294. // // CloudMoolah Hash Key
  295. // builder.Configure<IMoolahConfiguration>().hashKey = "cc";
  296. // // This enables the CloudMoolah test mode for local testing.
  297. // // You would remove this, or set to CloudMoolahMode.Production, before building your release package.
  298. // builder.Configure<IMoolahConfiguration>().SetMode(CloudMoolahMode.AlwaysSucceed);
  299. // // This records whether we are using Cloud Moolah IAP.
  300. // // Cloud Moolah requires logging in to access your Digital Wallet, so:
  301. // // A) IAPDemo (this) displays the Cloud Moolah GUI button for Cloud Moolah
  302. // m_IsCloudMoolahStoreSelected = Application.platform == RuntimePlatform.Android && module.appStore == AppStore.CloudMoolah;
  303. // // UnityChannel, provides access to Xiaomi MiPay.
  304. // // Products are required to be set in the IAP Catalog window. The file "MiProductCatalog.prop"
  305. // // is required to be generated into the project's
  306. // // Assets/Plugins/Android/assets folder, based off the contents of the
  307. // // IAP Catalog window, for MiPay.
  308. // m_IsUnityChannelSelected = Application.platform == RuntimePlatform.Android && module.appStore == AppStore.XiaomiMiPay;
  309. // // UnityChannel supports receipt validation through a backend fetch.
  310. // builder.Configure<IUnityChannelConfiguration>().fetchReceiptPayloadOnPurchase = m_FetchReceiptPayloadOnPurchase;
  311. // // Define our products.
  312. // // Either use the Unity IAP Catalog, or manually use the ConfigurationBuilder.AddProduct API.
  313. // // Use IDs from both the Unity IAP Catalog and hardcoded IDs via the ConfigurationBuilder.AddProduct API.
  314. // // Use the products defined in the IAP Catalog GUI.
  315. // // E.g. Menu: "Window" > "Unity IAP" > "IAP Catalog", then add products, then click "App Store Export".
  316. // var catalog = ProductCatalog.LoadDefaultCatalog();
  317. // foreach (var product in catalog.allProducts) {
  318. // if (product.allStoreIDs.Count > 0) {
  319. // var ids = new IDs();
  320. // foreach (var storeID in product.allStoreIDs) {
  321. // ids.Add(storeID.id, storeID.store);
  322. // }
  323. // builder.AddProduct(product.id, product.type, ids);
  324. // } else {
  325. // builder.AddProduct(product.id, product.type);
  326. // }
  327. // }
  328. // // In this case our products have the same identifier across all the App stores,
  329. // // except on the Mac App store where product IDs cannot be reused across both Mac and
  330. // // iOS stores.
  331. // // So on the Mac App store our products have different identifiers,
  332. // // and we tell Unity IAP this by using the IDs class.
  333. // builder.AddProduct("100.gold.coins", ProductType.Consumable, new IDs
  334. // {
  335. // {"100.gold.coins.mac", MacAppStore.Name},
  336. // {"000000596586", TizenStore.Name},
  337. // {"com.ff", MoolahAppStore.Name},
  338. // }
  339. //#if USE_PAYOUTS
  340. // , new PayoutDefinition(PayoutType.Currency, "gold", 100)
  341. //#endif //USE_PAYOUTS
  342. // );
  343. // builder.AddProduct("500.gold.coins", ProductType.Consumable, new IDs
  344. // {
  345. // {"500.gold.coins.mac", MacAppStore.Name},
  346. // {"000000596581", TizenStore.Name},
  347. // {"com.ee", MoolahAppStore.Name},
  348. // }
  349. //#if USE_PAYOUTS
  350. // , new PayoutDefinition(PayoutType.Currency, "gold", 500)
  351. //#endif //USE_PAYOUTS
  352. // );
  353. // builder.AddProduct("sword", ProductType.NonConsumable, new IDs
  354. // {
  355. // {"sword.mac", MacAppStore.Name},
  356. // {"000000596583", TizenStore.Name},
  357. // }
  358. //#if USE_PAYOUTS
  359. // , new List<PayoutDefinition> {
  360. // new PayoutDefinition(PayoutType.Item, "", 1, "item_id:76543"),
  361. // new PayoutDefinition(PayoutType.Currency, "gold", 50)
  362. // }
  363. //#endif //USE_PAYOUTS
  364. // );
  365. // builder.AddProduct("subscription", ProductType.Subscription, new IDs
  366. // {
  367. // {"subscription.mac", MacAppStore.Name}
  368. // });
  369. // // Write Amazon's JSON description of our products to storage when using Amazon's local sandbox.
  370. // // This should be removed from a production build.
  371. // builder.Configure<IAmazonConfiguration>().WriteSandboxJSON(builder.products);
  372. // // This enables simulated purchase success for Samsung IAP.
  373. // // You would remove this, or set to SamsungAppsMode.Production, before building your release package.
  374. // builder.Configure<ISamsungAppsConfiguration>().SetMode(SamsungAppsMode.AlwaysSucceed);
  375. // // This records whether we are using Samsung IAP. Currently ISamsungAppsExtensions.RestoreTransactions
  376. // // displays a blocking Android Activity, so:
  377. // // A) Unity IAP does not automatically restore purchases on Samsung Galaxy Apps
  378. // // B) IAPDemo (this) displays the "Restore" GUI button for Samsung Galaxy Apps
  379. // m_IsSamsungAppsStoreSelected = Application.platform == RuntimePlatform.Android && module.appStore == AppStore.SamsungApps;
  380. // // This selects the GroupId that was created in the Tizen Store for this set of products
  381. // // An empty or non-matching GroupId here will result in no products available for purchase
  382. // builder.Configure<ITizenStoreConfiguration>().SetGroupId("100000085616");
  383. // #if RECEIPT_VALIDATION
  384. // string appIdentifier;
  385. // #if UNITY_5_6_OR_NEWER
  386. // appIdentifier = Application.identifier;
  387. // #else
  388. // appIdentifier = Application.bundleIdentifier;
  389. // #endif
  390. // validator = new CrossPlatformValidator(GooglePlayTangle.Data(), AppleTangle.Data(),
  391. // UnityChannelTangle.Data(), appIdentifier);
  392. // #endif
  393. // Action initializeUnityIap = () =>
  394. // {
  395. // // Now we're ready to initialize Unity IAP.
  396. // UnityPurchasing.Initialize(this, builder);
  397. // };
  398. // bool needExternalLogin = m_IsUnityChannelSelected;
  399. // if (!needExternalLogin)
  400. // {
  401. // initializeUnityIap();
  402. // }
  403. // else
  404. // {
  405. // // Call UnityChannel initialize and (later) login asynchronously
  406. // // UnityChannel configuration settings. Required for Xiaomi MiPay.
  407. // // Collect this app configuration from the Unity Developer website at
  408. // // [2017-04-17 PENDING - Contact support representative]
  409. // // https://developer.cloud.unity3d.com/ providing your Xiaomi MiPay App
  410. // // ID, App Key, and App Secret. This permits Unity to proxy from the
  411. // // user's device into the MiPay system.
  412. // // IMPORTANT PRE-BUILD STEP: For mandatory Chinese Government app auditing
  413. // // and for MiPay testing, enable debug mode (test mode)
  414. // // using the `AppInfo.debug = true;` when initializing Unity Channel.
  415. // AppInfo unityChannelAppInfo = new AppInfo();
  416. // unityChannelAppInfo.appId = "abc123appId";
  417. // unityChannelAppInfo.appKey = "efg456appKey";
  418. // unityChannelAppInfo.clientId = "hij789clientId";
  419. // unityChannelAppInfo.clientKey = "klm012clientKey";
  420. // unityChannelAppInfo.debug = false;
  421. // // Shared handler for Unity Channel initialization, here, and login, later
  422. // unityChannelLoginHandler = new UnityChannelLoginHandler();
  423. // unityChannelLoginHandler.initializeFailedAction = (string message) =>
  424. // {
  425. // Debug.LogError("Failed to initialize and login to UnityChannel: " + message);
  426. // };
  427. // unityChannelLoginHandler.initializeSucceededAction = () =>
  428. // {
  429. // initializeUnityIap();
  430. // };
  431. // StoreService.Initialize(unityChannelAppInfo, unityChannelLoginHandler);
  432. // }
  433. // }
  434. // // For handling initialization and login of UnityChannel, returning control to our store after.
  435. // class UnityChannelLoginHandler : ILoginListener
  436. // {
  437. // internal Action initializeSucceededAction;
  438. // internal Action<string> initializeFailedAction;
  439. // internal Action<UserInfo> loginSucceededAction;
  440. // internal Action<string> loginFailedAction;
  441. // public void OnInitialized()
  442. // {
  443. // initializeSucceededAction();
  444. // }
  445. // public void OnInitializeFailed(string message)
  446. // {
  447. // initializeFailedAction(message);
  448. // }
  449. // public void OnLogin(UserInfo userInfo)
  450. // {
  451. // loginSucceededAction(userInfo);
  452. // }
  453. // public void OnLoginFailed(string message)
  454. // {
  455. // loginFailedAction(message);
  456. // }
  457. // }
  458. // /// <summary>
  459. // /// This will be called after a call to IAppleExtensions.RestoreTransactions().
  460. // /// </summary>
  461. // private void OnTransactionsRestored(bool success)
  462. // {
  463. // Debug.Log("Transactions restored.");
  464. // }
  465. // /// <summary>
  466. // /// iOS Specific.
  467. // /// This is called as part of Apple's 'Ask to buy' functionality,
  468. // /// when a purchase is requested by a minor and referred to a parent
  469. // /// for approval.
  470. // ///
  471. // /// When the purchase is approved or rejected, the normal purchase events
  472. // /// will fire.
  473. // /// </summary>
  474. // /// <param name="item">Item.</param>
  475. // private void OnDeferred(Product item)
  476. // {
  477. // Debug.Log("Purchase deferred: " + item.definition.id);
  478. // }
  479. // private void InitUI(IEnumerable<Product> items)
  480. // {
  481. // // Disable the UI while IAP is initializing
  482. // // See also UpdateInteractable()
  483. // m_InteractableSelectable = GetDropdown(); // References any one of the disabled components
  484. // // Show Restore button on supported platforms
  485. // if (! (NeedRestoreButton()) )
  486. // {
  487. // GetRestoreButton().gameObject.SetActive(false);
  488. // }
  489. // // Show Register, Login, and Validate buttons on supported platform
  490. // GetRegisterButton().gameObject.SetActive(NeedRegisterButton());
  491. // GetLoginButton().gameObject.SetActive(NeedLoginButton());
  492. // GetValidateButton().gameObject.SetActive(NeedValidateButton());
  493. // foreach (var item in items)
  494. // {
  495. // // Add initial pre-IAP-initialization content. Update later in OnInitialized.
  496. // var description = string.Format("{0} - {1}", item.definition.id, item.definition.type);
  497. // GetDropdown().options.Add(new Dropdown.OptionData(description));
  498. // }
  499. // // Ensure I render the selected list element
  500. // GetDropdown().RefreshShownValue();
  501. // GetDropdown().onValueChanged.AddListener((int selectedItem) => {
  502. // Debug.Log("OnClickDropdown item " + selectedItem);
  503. // m_SelectedItemIndex = selectedItem;
  504. // });
  505. // // Initialize my button event handling
  506. // GetBuyButton().onClick.AddListener(() => {
  507. // if (m_PurchaseInProgress == true) {
  508. // Debug.Log("Please wait, purchasing ...");
  509. // return;
  510. // }
  511. // // For platforms needing Login, games utilizing a connected backend
  512. // // game server may wish to login.
  513. // // Standalone games may not need to login.
  514. // if (NeedLoginButton() && m_IsLoggedIn == false)
  515. // {
  516. // Debug.LogWarning("Purchase notifications will not be forwarded server-to-server. Login incomplete.");
  517. // }
  518. // // Don't need to draw our UI whilst a purchase is in progress.
  519. // // This is not a requirement for IAP Applications but makes the demo
  520. // // scene tidier whilst the fake purchase dialog is showing.
  521. // m_PurchaseInProgress = true;
  522. // m_Controller.InitiatePurchase(m_Controller.products.all[m_SelectedItemIndex], "aDemoDeveloperPayload");
  523. // });
  524. // if (GetRestoreButton() != null)
  525. // {
  526. // GetRestoreButton().onClick.AddListener(() => {
  527. // if (m_IsCloudMoolahStoreSelected)
  528. // {
  529. // if (m_IsLoggedIn == false)
  530. // {
  531. // Debug.LogError("CloudMoolah purchase restoration aborted. Login incomplete.");
  532. // }
  533. // else
  534. // {
  535. // // Restore abnornal transaction identifer, if Client don't receive transaction identifer.
  536. // m_MoolahExtensions.RestoreTransactionID((RestoreTransactionIDState restoreTransactionIDState) => {
  537. // Debug.Log("restoreTransactionIDState = " + restoreTransactionIDState.ToString());
  538. // bool success =
  539. // restoreTransactionIDState != RestoreTransactionIDState.RestoreFailed &&
  540. // restoreTransactionIDState != RestoreTransactionIDState.NotKnown;
  541. // OnTransactionsRestored(success);
  542. // });
  543. // }
  544. // }
  545. // else if (m_IsSamsungAppsStoreSelected)
  546. // {
  547. // m_SamsungExtensions.RestoreTransactions(OnTransactionsRestored);
  548. // }
  549. // else if (Application.platform == RuntimePlatform.WSAPlayerX86 ||
  550. // Application.platform == RuntimePlatform.WSAPlayerX64 ||
  551. // Application.platform == RuntimePlatform.WSAPlayerARM)
  552. // {
  553. // m_MicrosoftExtensions.RestoreTransactions();
  554. // }
  555. // else
  556. // {
  557. // m_AppleExtensions.RestoreTransactions(OnTransactionsRestored);
  558. // }
  559. // });
  560. // }
  561. // if (GetLoginButton() != null)
  562. // {
  563. // if (m_IsUnityChannelSelected)
  564. // {
  565. // GetLoginButton().onClick.AddListener(() =>
  566. // {
  567. // unityChannelLoginHandler.loginSucceededAction = (UserInfo userInfo) =>
  568. // {
  569. // m_IsLoggedIn = true;
  570. // Debug.LogFormat("Succeeded logging into UnityChannel. channel {0}, userId {1}, userLoginToken {2} ",
  571. // userInfo.channel, userInfo.userId, userInfo.userLoginToken);
  572. // };
  573. // unityChannelLoginHandler.loginFailedAction = (string message) =>
  574. // {
  575. // m_IsLoggedIn = false;
  576. // Debug.LogError("Failed logging into UnityChannel. " + message);
  577. // };
  578. // StoreService.Login(unityChannelLoginHandler);
  579. // });
  580. // }
  581. // }
  582. // // For local validation, see ProcessPurchase.
  583. // if (GetValidateButton() != null)
  584. // {
  585. // if (m_IsUnityChannelSelected)
  586. // {
  587. // GetValidateButton()
  588. // .onClick.AddListener(() =>
  589. // {
  590. // string txId = m_LastTransationID;
  591. // m_UnityChannelExtensions.ValidateReceipt(txId, (bool success, string signData, string signature) =>
  592. // {
  593. // Debug.LogFormat("ValidateReceipt transactionId {0}, success {1}, signData {2}, signature {3}",
  594. // txId, success, signData, signature);
  595. // // May use signData and signature results to validate server-to-server
  596. // });
  597. // });
  598. // }
  599. // }
  600. // }
  601. // public void UpdateHistoryUI()
  602. // {
  603. // if (m_Controller == null)
  604. // {
  605. // return;
  606. // }
  607. // var itemText = "Item\n\n";
  608. // var countText = "Purchased\n\n";
  609. // foreach (var item in m_Controller.products.all) {
  610. // // Collect history status report
  611. // itemText += "\n\n" + item.definition.id;
  612. // countText += "\n\n";
  613. //#if DELAY_CONFIRMATION
  614. // if (m_PendingProducts.Contains(item.definition.id))
  615. // countText += "(Pending) ";
  616. //#endif
  617. // countText += item.hasReceipt.ToString();
  618. // }
  619. // // Show history
  620. // GetText(false).text = itemText;
  621. // GetText(true).text = countText;
  622. // }
  623. // protected void UpdateInteractable()
  624. // {
  625. // if (m_InteractableSelectable == null)
  626. // {
  627. // return;
  628. // }
  629. // bool interactable = m_Controller != null;
  630. // if (interactable != m_InteractableSelectable.interactable)
  631. // {
  632. // if (GetRestoreButton() != null)
  633. // {
  634. // GetRestoreButton().interactable = interactable;
  635. // }
  636. // GetBuyButton().interactable = interactable;
  637. // GetDropdown().interactable = interactable;
  638. // GetRegisterButton().interactable = interactable;
  639. // GetLoginButton().interactable = interactable;
  640. // }
  641. // }
  642. // public void Update()
  643. // {
  644. // UpdateInteractable();
  645. // }
  646. // private bool NeedRestoreButton()
  647. // {
  648. // return Application.platform == RuntimePlatform.IPhonePlayer ||
  649. // Application.platform == RuntimePlatform.OSXPlayer ||
  650. // Application.platform == RuntimePlatform.tvOS ||
  651. // Application.platform == RuntimePlatform.WSAPlayerX86 ||
  652. // Application.platform == RuntimePlatform.WSAPlayerX64 ||
  653. // Application.platform == RuntimePlatform.WSAPlayerARM ||
  654. // m_IsSamsungAppsStoreSelected ||
  655. // m_IsCloudMoolahStoreSelected;
  656. // }
  657. // private bool NeedRegisterButton()
  658. // {
  659. // // Deprecated
  660. // return false;
  661. // }
  662. // private bool NeedLoginButton()
  663. // {
  664. // return m_IsUnityChannelSelected;
  665. // }
  666. // private bool NeedValidateButton()
  667. // {
  668. // return m_IsUnityChannelSelected;
  669. // }
  670. // private Text GetText(bool right)
  671. // {
  672. // var which = right ? "TextR" : "TextL";
  673. // return GameObject.Find(which).GetComponent<Text>();
  674. // }
  675. // private Dropdown GetDropdown()
  676. // {
  677. // return GameObject.Find("Dropdown").GetComponent<Dropdown>();
  678. // }
  679. // private Button GetBuyButton()
  680. // {
  681. // return GameObject.Find("Buy").GetComponent<Button>();
  682. // }
  683. // /// <summary>
  684. // /// Gets the restore button when available
  685. // /// </summary>
  686. // /// <returns><c>null</c> or the restore button.</returns>
  687. // private Button GetRestoreButton()
  688. // {
  689. // return GetButton ("Restore");
  690. // }
  691. // private Button GetRegisterButton()
  692. // {
  693. // return GetButton ("Register");
  694. // }
  695. // private Button GetLoginButton()
  696. // {
  697. // return GetButton ("Login");
  698. // }
  699. // private Button GetValidateButton()
  700. // {
  701. // return GetButton ("Validate");
  702. // }
  703. // private Button GetButton(string buttonName)
  704. // {
  705. // GameObject obj = GameObject.Find(buttonName);
  706. // if (obj != null)
  707. // {
  708. // return obj.GetComponent <Button>();
  709. // }
  710. // else
  711. // {
  712. // return null;
  713. // }
  714. // }
  715. // private void LogProductDefinitions()
  716. // {
  717. // var products = m_Controller.products.all;
  718. // foreach (var product in products) {
  719. //#if UNITY_5_6_OR_NEWER
  720. // Debug.Log(string.Format("id: {0}\nstore-specific id: {1}\ntype: {2}\nenabled: {3}\n", product.definition.id, product.definition.storeSpecificId, product.definition.type.ToString(), product.definition.enabled ? "enabled" : "disabled"));
  721. //#else
  722. // Debug.Log(string.Format("id: {0}\nstore-specific id: {1}\ntype: {2}\n", product.definition.id, product.definition.storeSpecificId, product.definition.type.ToString()));
  723. //#endif
  724. // }
  725. // }
  726. //}