示例#1
0
    public void Initialize(AppStore appStore, List <ProductDefinition> products)
    {
        // If we have already connected to Purchasing ...
        if (IsInitialized())
        {
            // ... we are done here.
            return;
        }
        standardPurchasingModule = StandardPurchasingModule.Instance(appStore);
        // Create a builder, first passing in a suite of Unity provided stores.
        var builder = ConfigurationBuilder.Instance(standardPurchasingModule);

        //// Add a product to sell / restore by way of its identifier, associating the general identifier
        //// with its store-specific identifiers.
        //builder.AddProduct(kProductIDConsumable, ProductType.Consumable);
        //// Continue adding the non-consumable product.
        //builder.AddProduct(kProductIDNonConsumable, ProductType.NonConsumable);
        //// And finish adding the subscription product. Notice this uses store-specific IDs, illustrating
        //// if the Product ID was configured differently between Apple and Google stores. Also note that
        //// one uses the general kProductIDSubscription handle inside the game - the store-specific IDs
        //// must only be referenced here.
        ////builder.AddProduct(kProductIDSubscription, ProductType.Subscription, new IDs(){
        ////        { kProductNameAppleSubscription, AppleAppStore.Name },
        ////        { kProductNameGooglePlaySubscription, GooglePlay.Name },
        ////    });
        builder.AddProducts(products);
        // Kick off the remainder of the set-up with an asynchrounous call, passing the configuration
        // and this class' instance. Expect a response either in OnInitialized or OnInitializeFailed.
        UnityPurchasing.Initialize(this, builder);
    }
示例#2
0
        async void UpdateRatingMessage()
        {
            var count = await AppStore.GetRatingCount();

            if (count < 0)
            {
                return;
            }
            string message = "";

            if (count == 0)
            {
                message = Strings.NobodyHasRatedYet;
            }
            else if (count == 1)
            {
                message = Strings.OnlyOnePersonHasRatedThisVersion;
            }
            else if (count < 50)
            {
                string only = Strings.Only;
                message = $"{Strings.Only} {count} {Strings.PeopleHaveRatedThisVersion}";
            }
            else
            {
                message = $"{count} {Strings.PeopleHaveRatedThisVersion}";
            }
            ratingMessage.Caption = message;
            this.ReloadData();
        }
        internal static AppStore TryTargetAndroidStore(AppStore target)
        {
            if (!target.IsAndroid())
            {
                throw new ArgumentException(string.Format("AppStore parameter ({0}) must be an Android app store", target));
            }

            if (target == AppStore.UDP)
            {
                if (!s_udpAvailable || (!IsUdpUmpPackageInstalled() && !IsUdpAssetStorePackageInstalled()) || !UdpSynchronizationApi.CheckUdpCompatibility())
                {
                    UdpInstaller.PromptUdpInstallation();
                    return(ConfiguredAppStore());
                }
            }

            ConfigureProject(target);
            SaveConfig(target);
            OnAndroidTargetChange?.Invoke(target);

            var targetString = Enum.GetName(typeof(AppStore), target);

            GenericEditorDropdownSelectEventSenderHelpers.SendIapMenuSelectTargetStoreEvent(targetString);

            return(ConfiguredAppStore());
        }
        public void WarnInvalidStore(AppStore currentAppStore)
        {
            var warningMsg = $"The cross-platform validator is not implemented for the currently selected store: {currentAppStore}. \n" +
                             "Build the project for Android, iOS, macOS, or tvOS and use the Google Play Store or Apple App Store. See README for more information.";

            Debug.LogWarning(warningMsg);
            warningText.text = warningMsg;
        }
        private static void SaveConfig(AppStore enabled)
        {
            var configToSave = new StoreConfiguration(enabled);

            File.WriteAllText(ModePath, StoreConfiguration.Serialize(configToSave));
            AssetDatabase.ImportAsset(ModePath);
            config = configToSave;
        }
示例#6
0
        private IEnumerable <AppStore> find(AppStore app)
        {
            var q = from a in this.UnitOfWork.DbContext.Set <AppStore>()
                    where a.AppID == app.AppID
                    select a;

            return(q.AsNoTracking());
        }
示例#7
0
        void OnCurrentStoreTargetChanged(AppStore store)
        {
            var actualStore = UnityPurchasingEditor.TryTargetAndroidStore(store);

            if (actualStore != store)
            {
                OnAndroidTargetChange(actualStore);
            }
        }
示例#8
0
 async Task SearchEvents()
 {
     if (Search.StartDate != null && Search.EndDate != null && Search.StartDate > Search.EndDate)
     {
         AppStore.AddNotification(new NotificationMessage("Le date non sono corrette", NotificationMessage.MessageType.Warning));
     }
     else
     {
         ReportLists = await Http.GetReportConfirmedIntervalledAsync(Search.StartDate.ToLocalTime(), Search.EndDate.ToLocalTime().EndOfDay());
     }
 }
示例#9
0
 /// <summary>
 /// Target a specified Android store.
 /// This sets the correct plugin importer settings for the store
 /// and writes the choice to BillingMode.json so the player
 /// can choose the correct store API at runtime.
 /// </summary>
 public static void TargetAndroidStore(AppStore target)
 {
     if (((int)target < (int)AppStoreMeta.AndroidStoreStart || (int)target > (int)AppStoreMeta.AndroidStoreEnd) &&
         target != AppStore.NotSpecified)
     {
         throw new ArgumentException(string.Format("AppStore parameter ({0}) must be an Android app store", target));
     }
     ConfigureProject(target);
     UpdateCheckmarks(target);
     SaveConfig(target);
 }
 internal StandardPurchasingModule(IUtil util, IAsyncWebUtil webUtil, ILogger logger,
                                   INativeStoreProvider nativeStoreProvider, RuntimePlatform platform, AppStore android)
 {
     this.util             = util;
     this.webUtil          = webUtil;
     this.logger           = logger;
     m_NativeStoreProvider = nativeStoreProvider;
     m_RuntimePlatform     = platform;
     useFakeStoreUIMode    = FakeStoreUIMode.Default;
     useFakeStoreAlways    = false;
     m_AppStorePlatform    = android;
 }
示例#11
0
 static void Main(string[] args)
 {
     dispatcher = new Dispatcher();
     appStore   = new AppStore(dispatcher);
     appStore.Register();
     appStore.Subscribe(AppStore.EVENT_NAME_CHANGED, OnNameChange);
     appStore.Subscribe(AppStore.EVENT_NAME_CHANGED, (sender, e) =>
     {
         Console.WriteLine("Using Annonymous function");
     });
     dispatcher.Dispatch <NameChangeAction>(new NameChangeAction("Hola"));
 }
示例#12
0
        async Task Export()
        {
            var response = await Http.GenerateReportEvents(Search.StartDate, Search.EndDate);

            if (response.IsSuccessStatusCode)
            {
                AppStore.AddNotification(new NotificationMessage("Il report verrà inviato via mail agli amministratori", NotificationMessage.MessageType.Info));
            }
            else
            {
                AppStore.AddNotification(new NotificationMessage("Errore generazione del report", new Exception(response.ReasonPhrase)));
            }
        }
示例#13
0
        void OnAndroidTargetChange(AppStore appStore)
        {
            if (!appStore.IsAndroid())
            {
                return;
            }

            var field = GetTagContainer(currentStoreSection) as IMGUIContainer;

            if (field != null && currentStoreTargetContainer != null && currentStoreTargetContainer.container == field)
            {
                currentStoreTargetContainer.index = BuildTargetGroup.Android.ToAppStores().IndexOf(appStore);
            }
        }
示例#14
0
        public static void TargetAndroidStore(AndroidStore target)
        {
            AppStore appStore = AppStore.NotSpecified;

            try
            {
                appStore = (AppStore)Enum.Parse(typeof(AppStore), target.ToString());
            }
            catch (Exception)
            {
                // No-op
            }
            TargetAndroidStore(appStore);
        }
        public static StandardPurchasingModule Instance(AndroidStore androidStore)
        {
            AppStore store = AppStore.NotSpecified;

            try
            {
                store = (AppStore)Enum.Parse(typeof(AppStore), androidStore.ToString());
            }
            catch (Exception)
            {
                // No-op
            }

            return(Instance(store));
        }
示例#16
0
        /// <summary>
        /// Creates an instance of StandardPurchasingModule or retrieves the existing one, specifying a type of App store.
        /// </summary>
        /// <param name="androidStore"> The type of Android Store with which to create the instance. </param>
        /// <returns> The existing instance or the one just created. </returns>
        public static StandardPurchasingModule Instance(AppStore androidStore)
        {
            if (null == ModuleInstance)
            {
                var logger = UnityEngine.Debug.unityLogger;
                logger.Log("UnityIAP Version: " + k_PackageVersion);
                var gameObject = new GameObject("IAPUtil");
                Object.DontDestroyOnLoad(gameObject);
                gameObject.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector;
                var util    = gameObject.AddComponent <UnityUtil> ();
                var webUtil = gameObject.AddComponent <AsyncWebUtil>();

                var textAsset             = (Resources.Load("BillingMode") as TextAsset);
                StoreConfiguration config = null;
                if (null != textAsset)
                {
                    config = StoreConfiguration.Deserialize(textAsset.text);
                }

                // No Android target specified at runtime, use the build time setting.
                if (androidStore == AppStore.NotSpecified)
                {
                    // Default to Google Play if we don't have a build time store selection.
                    androidStore = AppStore.GooglePlay;

                    if (null != config)
                    {
                        var buildTimeStore = config.androidStore;
                        if (buildTimeStore != AppStore.NotSpecified)
                        {
                            androidStore = buildTimeStore;
                        }
                    }
                }

                ModuleInstance = new StandardPurchasingModule(
                    util,
                    webUtil,
                    logger,
                    new NativeStoreProvider(),
                    Application.platform,
                    androidStore,
                    false,
                    Application.persistentDataPath);
            }

            return(ModuleInstance);
        }
 internal StandardPurchasingModule(IUtil util, IAsyncWebUtil webUtil, ILogger logger,
                                   INativeStoreProvider nativeStoreProvider, RuntimePlatform platform, AppStore android, bool useCloudCatalog,
                                   string persistentDataPath)
 {
     this.util             = util;
     this.webUtil          = webUtil;
     this.logger           = logger;
     m_NativeStoreProvider = nativeStoreProvider;
     m_RuntimePlatform     = platform;
     useFakeStoreUIMode    = FakeStoreUIMode.Default;
     useFakeStoreAlways    = false;
     m_AppStorePlatform    = android;
     m_UseCloudCatalog     = useCloudCatalog;
     m_persistentDataPath  = persistentDataPath;
     Promo.InitPromo(platform, logger, Version, util, webUtil);
 }
示例#18
0
        public int SetAppStore(AppStore app)
        {
            var entities = this.find(app);

            // Update
            if (entities.Any())
            {
                this.UnitOfWork.Repository <AppStore>().Update(app);
                return(this.UnitOfWork.SaveChanges());
            }
            else
            {
                this.UnitOfWork.Repository <AppStore>().Add(app);
                return(this.UnitOfWork.SaveChanges());
            }
        }
        private void InstallFile(int parentMessageId, AppStore appCopy, bool overwrite, XmlNode ndChild, string fullFile, string fileName, string parentFolder, bool overWriteFile)
        {
            var spFille = oWeb.GetFile(ApplicationInstallerHelpers.getAttribute(ndChild, "FullFile"));

            if (spFille.Exists)
            {
                if (overwrite || overWriteFile)
                {
                    try
                    {
                        if (!bVerifyOnly)
                        {
                            iInstallFile(fileName, parentFolder, fullFile, appCopy);
                        }

                        addMessage(ErrorLevels.NoError, "File: " + fileName, string.Empty, parentMessageId);
                    }
                    catch (Exception ex)
                    {
                        addMessage(ErrorLevels.Error, "File: " + fileName, "Error: " + ex.Message, parentMessageId);
                        Trace.WriteLine(ex.ToString());
                    }
                }
                else
                {
                    addMessage(ErrorLevels.Warning, "File: " + fileName, "File exists and can't overwrite", parentMessageId);
                }
            }
            else
            {
                try
                {
                    if (!bVerifyOnly)
                    {
                        iInstallFile(fileName, parentFolder, fullFile, appCopy);
                    }

                    addMessage(ErrorLevels.NoError, "File: " + fileName, string.Empty, parentMessageId);
                }
                catch (Exception ex)
                {
                    addMessage(ErrorLevels.Error, "File: " + fileName, "Error: " + ex.Message, parentMessageId);
                    Trace.WriteLine(ex.ToString());
                }
            }
        }
示例#20
0
        private void iInstallListsViewsWebparts(SPList oList, XmlNode ndList, int ParentMessageId, bool added)
        {
            var ndViews = ndList.SelectSingleNode("Views");

            if (ndViews != null)
            {
                var storeurl = CoreFunctions.getFarmSetting("workenginestore");

                ServicePointManager.ServerCertificateValidationCallback +=
                    delegate { return(true); };

                var copy = new AppStore();
                copy.Credentials = CoreFunctions.GetStoreCreds();
                copy.Url         = storeurl + "_vti_bin/appstore.asmx";

                if (bVerifyOnly)
                {
                    ParentMessageId = addMessage(0, "Checking WebParts", string.Empty, ParentMessageId);
                }
                else
                {
                    ParentMessageId = addMessage(0, "Updating WebParts", string.Empty, ParentMessageId);
                }

                var bInstallAll = false;
                bool.TryParse(ApplicationInstallerHelpers.getAttribute(ndViews, "InstallGridOnAllViews"), out bInstallAll);

                if (bInstallAll)
                {
                    addMessage(0, "Grid on All Views", string.Empty, ParentMessageId);
                }

                if (oList != null)
                {
                    foreach (SPView oView in oList.Views)
                    {
                        if (!oView.PersonalView)
                        {
                            var ndView = ndViews.SelectSingleNode("View[@Name='" + oView.Title + "']");

                            InstallListsViewsWebPartsInstall(oView, bInstallAll, copy, ParentMessageId);
                        }
                    }
                }
            }
        }
示例#21
0
        private static void UpdateCheckmarks(AppStore target)
        {
            var assemblies = AppDomain.CurrentDomain.GetAssemblies();

            if (null == Array.Find <System.Reflection.Assembly>(assemblies, (a) => a.GetName().Name == "UnityEngine.Purchasing"))
            {
                // If the assembly is not available, the menu items below won't exist
                Debug.LogError("The Unity IAP plugin is installed, but Unity IAP is disabled. Please enable Unity IAP in the Services window.");
                return;
            }

            // GooglePlay is default when none specified

            Menu.SetChecked(AmazonMenuItem, target == AppStore.AmazonAppStore);
            Menu.SetChecked(GooglePlayMenuItem, target == AppStore.GooglePlay || target == AppStore.NotSpecified);
            Menu.SetChecked(SamsungAppsMenuItem, target == AppStore.SamsungApps);
            Menu.SetChecked(UdpMenuItem, target == AppStore.UDP);
        }
        /// <summary>
        /// Target a specified Android store.
        /// This sets the correct plugin importer settings for the store
        /// and writes the choice to BillingMode.json so the player
        /// can choose the correct store API at runtime.
        /// </summary>
        /// <param name="target">App store to enable for next build</param>
        public static void TargetAndroidStore(AppStore target)
        {
            if (((int)target < (int)AppStoreMeta.AndroidStoreStart || (int)target > (int)AppStoreMeta.AndroidStoreEnd) &&
                target != AppStore.NotSpecified)
            {
                throw new ArgumentException(string.Format("AppStore parameter ({0}) must be an Android app store", target));
            }

            if (target == AppStore.SamsungApps)
            {
                Debug.LogWarning(
                    AppStore.SamsungApps +
                    " is obsolete and will be removed in v4. Please Use Unity Distribution Platform for Samsung Galaxy Apps support");
            }
            ConfigureProject(target);
            UpdateCheckmarks(target);
            SaveConfig(target);
        }
示例#23
0
        public void Init()
        {
            var module = StandardPurchasingModule.Instance();

            appStore = module.appStore;
            var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());

            foreach (var t in TableShop.GetAll())
            {
                builder.AddProduct(t.productID, (ProductType)t.type, new IDs
                {
                    { t.productID, GooglePlay.Name },
                    { t.productID, AppleAppStore.Name }
                });
            }
            builder.Configure <IGooglePlayConfiguration>().SetPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt1lvHFO1vq2djnUEgv3PGrTsieVKtLUIRSlW99wnqHZMYLRoXnK0qOnWU6Lz/jt07LkktqJzWrW+OE/w67VtLJMrycBaA0eCDqErr62pg4HkXK4tS9+0oJJxJ9pvr+QACLigJlHefPGtoZ+JumUILnxM6dPwW7xalxaCTmhSpfg3CVZ75NXTmIx4X5qLAHFPOCPrjdTTZPdX7zZMRTdIYAAseXn4X+BE2gRhhyCVA0T9+m1AD8lC+wftuQz+xRksYjEj9XgNJJ3A0Z9QKr3MZoyqYQ0+6HPpNzKY6owf7t3fix36oJl4OYu+99ksO2p2oqVrpbPSJVWFkmbJRrFepQIDAQAB");
            builder.useCatalogProvider = false;
            UnityPurchasing.Initialize(this, builder);
        }
示例#24
0
        public INativeStore GetAndroidStore(IUnityCallback callback, AppStore store, IPurchasingBinder binder, IUtil util)
        {
            INativeStore nativeStore;

            try
            {
                nativeStore = GetAndroidStoreHelper(callback, store, binder, util);
            }
            catch (Exception e)
            {
                throw new NotSupportedException("Failed to bind to native store: " + e.ToString());
            }

            if (nativeStore != null)
            {
                return(nativeStore);
            }

            throw new NotImplementedException();
        }
        async Task Success()
        {
            var result = await Http.CreateEvent(EventViewModel).ConfigureAwait(false);

            if (result.IsSuccessStatusCode)
            {
                string resultId = await result.Content.ReadAsStringAsync().ConfigureAwait(false);

                if (AppStore.EventImage != null)
                {
                    await Http.UploadEventImage(EventViewModel.Id, AppStore.EventImage).ConfigureAwait(false);
                }
                AppStore.AddNotification(new NotificationMessage("Evento sottomesso", NotificationMessage.MessageType.Success));
            }
            else
            {
                string error = await result.Content.ReadAsStringAsync();

                AppStore.AddNotification(new NotificationMessage("Errore nella creazione", NotificationMessage.MessageType.Danger));
            }
        }
示例#26
0
        private INativeStore GetAndroidStoreHelper(IUnityCallback callback, AppStore store, IPurchasingBinder binder,
                                                   IUtil util)
        {
            switch (store)
            {
            case AppStore.AmazonAppStore:
                using (var pluginClass = new AndroidJavaClass("com.unity.purchasing.amazon.AmazonPurchasing"))
                {
                    // Switch Android callbacks to the scripting thread, via ScriptingUnityCallback.
                    var proxy    = new JavaBridge(new ScriptingUnityCallback(callback, util));
                    var instance = pluginClass.CallStatic <AndroidJavaObject> ("instance", proxy);
                    // Hook up our amazon specific functionality.
                    var extensions = new AmazonAppStoreStoreExtensions(instance);
                    binder.RegisterExtension <IAmazonExtensions> (extensions);
                    binder.RegisterConfiguration <IAmazonConfiguration> (extensions);
                    return(new AndroidJavaStore(instance));
                }

            case AppStore.UDP:
            {
                Type udpIapBridge = UdpIapBridgeInterface.GetClassType();
                if (udpIapBridge != null)
                {
                    UDPImpl     udpImpl     = new UDPImpl();
                    UDPBindings udpBindings = new UDPBindings();
                    udpImpl.SetNativeStore(udpBindings);
                    binder.RegisterExtension <IUDPExtensions>(udpImpl);
                    return(udpBindings);
                }
                else
                {
                    Debug.LogError("Cannot set Android target to UDP. Make sure you have installed UDP in your project");
                    throw new NotImplementedException();
                }
            }
            }

            throw new NotImplementedException();
        }
        async Task Success()
        {
            var result = await Http.CreateCommunity(CommunityViewModel).ConfigureAwait(false);

            if (result.IsSuccessStatusCode)
            {
                string resultId = await result.Content.ReadAsStringAsync().ConfigureAwait(false);

                if (AppStore.EventImage != null)
                {
                    string shortname = CommunityViewModel.Name.Replace(" ", "-").ToLowerInvariant();
                    await Http.UploadCommunityImage(shortname, AppStore.CommunityImage).ConfigureAwait(false);
                }
                AppStore.AddNotification(new NotificationMessage("Community sottomessa", NotificationMessage.MessageType.Success));
            }
            else
            {
                string error = await result.Content.ReadAsStringAsync();

                AppStore.AddNotification(new NotificationMessage("Errore nella creazione", NotificationMessage.MessageType.Danger));
            }
        }
示例#28
0
        async Task Success()
        {
            var e = new EventViewModel
            {
                Id            = EventViewModel.Id,
                StartDate     = EventViewModel.StartDate,
                EndDate       = EventViewModel.EndDate,
                CFP           = string.IsNullOrEmpty(EventViewModel.CFP.Url) ? null : EventViewModel.CFP,
                CommunityName = EventViewModel.Community.ShortName,
                Name          = EventViewModel.Name
            };

            if (!string.IsNullOrEmpty(EventViewModel.BuyTicket))
            {
                e.BuyTicket = EventViewModel.BuyTicket;
            }
            var responseUpdate = await Http.UpdateEvent(e).ConfigureAwait(false);

            if (responseUpdate.IsSuccessStatusCode)
            {
                if (AppStore.EventImage != null)
                {
                    var responseUploadMessage = await Http.UploadEventImage(e.Id, AppStore.EventImage).ConfigureAwait(false);

                    if (!responseUploadMessage.IsSuccessStatusCode)
                    {
                        AppStore.AddNotification(new NotificationMessage("Errore salvataggio", NotificationMessage.MessageType.Danger));
                    }
                    else
                    {
                        AppStore.AddNotification(new NotificationMessage("Evento salvato", NotificationMessage.MessageType.Success));
                    }
                }
                else
                {
                    AppStore.AddNotification(new NotificationMessage("Evento salvato", NotificationMessage.MessageType.Success));
                }
            }
        }
示例#29
0
    protected override void ExtraInit()
    {
        listener = new IAPStoreListener();


        List <ProductDefinition> products = new List <ProductDefinition>();


        foreach (var item in productDefinitions)
        {
            ProductType       productType = GoodsType2ProductType(item.goodsType);
            ProductDefinition p           = new ProductDefinition(item.goodsID, productType);
            products.Add(p);
        }
        AppStore appStore = (AppStore)Enum.Parse(typeof(AppStore), storeName.ToString());

        listener.Initialize(appStore, products);
        listener.onInitialized      = OnInitialized;
        listener.onInitializeFailed = OnInitializeFailed;
        listener.onPurchaseFailed   = OnPurchaseFailed;
        listener.onPurchaseSuccess  = OnPurchaseSuccess;
    }
        public override int GetHashCode()
        {
            int hash = 1;

            if (Uuid.Length != 0)
            {
                hash ^= Uuid.GetHashCode();
            }
            if (LoginType != 0)
            {
                hash ^= LoginType.GetHashCode();
            }
            if (AppVersion.Length != 0)
            {
                hash ^= AppVersion.GetHashCode();
            }
            if (AppStore.Length != 0)
            {
                hash ^= AppStore.GetHashCode();
            }
            if (DeviceModel.Length != 0)
            {
                hash ^= DeviceModel.GetHashCode();
            }
            if (DeviceCountry.Length != 0)
            {
                hash ^= DeviceCountry.GetHashCode();
            }
            if (DeviceLanguage.Length != 0)
            {
                hash ^= DeviceLanguage.GetHashCode();
            }
            if (_unknownFields != null)
            {
                hash ^= _unknownFields.GetHashCode();
            }
            return(hash);
        }
示例#31
0
        public static void Main(string[] args)
        {
            string filePath = null;
            if (args.Length == 0)
            {
                throw new ArgumentException("Should be called with a Json PlayDrone file to import.");
            }

            filePath = args[0];

            var log = new Logger();
            var appConverter = new FileReader(log);

            var apps = appConverter.FileToModel(filePath);
            var count = apps.Count();

            // Setup connection
            var connectionString = ConfigurationManager.ConnectionStrings["MarketDbConnectionString"];
            using (var connection = new SqlConnection(connectionString.ConnectionString))
            {
                // Initialise app store with logger and connection
                var appSqlStore = new AppStore(connection);
                var appStore = new AppLogger(appSqlStore, appSqlStore, log);
                var categorySqlStore = new CategoryStore();
                var categoryCacheStore = new CategoryCache(categorySqlStore, categorySqlStore);
                var categoryStore = new CategoryLogger(categoryCacheStore, categoryCacheStore, log);

                // Assuming apps are added in order to save multiple queries to the database.
                var existingAppCount = appStore.Count();

                // Loop through apps. App store will save every 100,000 apps
                var appsToSave = new List<Models.App>();
                var appCounter = 0;
                for (int i = existingAppCount; i < count; i++)
                {
                    // Get the app from the list.
                    var app = apps[i];

                    // Store the app category if it doesn't exist.
                    if (!categoryStore.Exists(app.category))
                    {
                        var category = new Models.Category { Id = Guid.NewGuid(), Name = app.category };
                        categoryStore.Save(category);
                    }

                    // Lookup app category id.
                    var categoryId = categoryStore.GetId(app.category);

                    app.id = Guid.NewGuid();
                    app.categoryId = categoryId;
                    appsToSave.Add(app);
                    log.LogOperation(string.Format("App {0}/{1} added: {2}", i + 1, count, app.app_id));
                    appCounter++;

                    // Save apps
                    if(appCounter >= 100000)
                    {
                        appStore.SaveMany(appsToSave);
                        appsToSave.Clear();
                        appCounter = 0;
                    }
                }

                // Save the remainder
                appStore.SaveMany(appsToSave);

                log.LogOperation("DONE!!!!");
            }
        }