유니티 공식 인앱결제(Unity IAP) 플러그인의 컬렉션 주의 사항
인앱 결제 부분을 유니티 공식 IAP 플러그인으로 작성하면서, PC/MAC에서는 별 문제 없이 인앱 결제 정보 초기화와 결제가 진행되었다. 그런데 실제 모바일 디바이스에서 동작시키면 '초기화'가 실행만 되고, 완료가 전혀 되지 않는다.
웹으로 모바일 장치에서 발생한 로그를 자동으로 출력해주는 유니티 퍼포먼스 서비스 덕분에 원인을 알았는데,

System.Collections.Generic.Dictionary`2[System.String,UnityEngine.Purchasing.Product].Add (System.String key, UnityEngine.Purchasing.Product value) System.Linq.Enumerable.ToDictionary[Product,String,Product] (IEnumerable`1 source, System.Func`2 keySelector, System.Func`2 elementSelector, IEqualityComparer`1 comparer) System.Linq.Enumerable.ToDictionary[Product,String] (IEnumerable`1 source, System.Func`2 keySelector, IEqualityComparer`1 comparer) System.Linq.Enumerable.ToDictionary[Product,String] (IEnumerable`1 source, System.Func`2 keySelector) UnityEngine.Purchasing.ProductCollection.AddProducts (IEnumerable`1 products) UnityEngine.Purchasing.ProductCollection..ctor (UnityEngine.Purchasing.Product[] products) UnityEngine.Purchasing.PurchasingManager.Initialize (IInternalStoreListener listener, System.Collections.Generic.HashSet`1 products) UnityEngine.Purchasing.UnityPurchasing+<Initialize>c__AnonStorey0.<>m__0 (System.Collections.Generic.HashSet`1 response) UnityEngine.Purchasing.UnityPurchasing.FetchAndMergeProducts (Boolean useCatalog, System.Collections.Generic.HashSet`1 localProductSet, ICatalogProvider catalog, System.Action`1 callback) UnityEngine.Purchasing.UnityPurchasing.Initialize (IStoreListener listener, UnityEngine.Purchasing.ConfigurationBuilder builder, ILogger logger, System.String persistentDatapath, IUnityAnalytics analytics, ICatalogProvider catalog) UnityEngine.Purchasing.UnityPurchasing.Initialize (IStoreListener listener, UnityEngine.Purchasing.ConfigurationBuilder builder) IAPManager.InitializePurchasing () IAPManager.Awake ()
유니티 API 내부에서 키 중복 에러가 발생한 것이다.
원인을 살펴보니, 유니티 IAP에 구매 가능한 상품을 추가할 때
builder.AddProduct("productID", ProductType.NonConsumable, newIDs() {{"com.company.iosapp.productID", AppleAppStore.Name} ,{ "com.company.androidapp.productID", GooglePlay.Name }});
같은 형식을 사용한다.
여기서 "productID"는 애플 앱스토어와 구글 플레이에 등록된 각각의 인앱상품 식별자를 일일이 판별하기 힘드니까 하나의 이름으로 부를 수 있게 해주는 용도다.
여기서 코딩 실수로 서로 다른 두 개의 "productID"에 같은 안드로이드 앱스토어 인앱상품 식별자를 연결한 것이다.
PC/MAC에서는 해당 예외 로그가 출력되지 않아 문제를 발견하지 못했다. 모바일 장치의 로그를 확인할 수 있었던 덕분에 원인을 찾았다.