From c43bfb51be5c0d70a0a5d9822d589543ceaf7dde Mon Sep 17 00:00:00 2001
From: gaoyuan <gaoyuan@gaoyuandeMacBook-Air.local>
Date: Sat, 12 Mar 2022 01:08:17 +0800
Subject: [PATCH] fix crash of sqlite in release mode

---
 Billing.Shared/App.cs                         |  10 +-
 Billing.Shared/Helper.cs                      |   8 +-
 Billing.Shared/Store/StoreHelper.cs           | 154 ++++++++++--------
 .../Billing.Android/Billing.Android.csproj    |   1 -
 .../Properties/AndroidManifest.xml            |   2 +-
 Billing/Billing.iOS/Billing.iOS.csproj        |  14 +-
 Billing/Billing.iOS/Info.plist                |  32 ++--
 7 files changed, 118 insertions(+), 103 deletions(-)

diff --git a/Billing.Shared/App.cs b/Billing.Shared/App.cs
index 9cddec6..3f52985 100644
--- a/Billing.Shared/App.cs
+++ b/Billing.Shared/App.cs
@@ -30,7 +30,6 @@ namespace Billing
             InitResources();
 
             MainPage = new MainShell();
-            //Shell.Current.GoToAsync("//Splash");
         }
 
         protected override void OnStart()
@@ -39,12 +38,13 @@ namespace Billing
             Helper.Debug($"cache folder: {StoreHelper.CacheFolder}");
         }
 
-        internal static async Task InitializeData()
+        public static async Task InitializeData()
         {
+            var instance = await StoreHelper.Instance;
             await Task.WhenAll(
-                Task.Run(async () => accounts = await StoreHelper.GetAccountsAsync()),
-                Task.Run(async () => categories = await StoreHelper.GetCategoriesAsync()),
-                Task.Run(async () => bills = await StoreHelper.GetBillsAsync()));
+                Task.Run(async () => accounts = await instance.GetListAsync<Account>()),
+                Task.Run(async () => categories = await instance.GetListAsync<Category>()),
+                Task.Run(async () => bills = await instance.GetListAsync<Bill>()));
         }
 
         protected override void OnResume()
diff --git a/Billing.Shared/Helper.cs b/Billing.Shared/Helper.cs
index b4fd510..3ee9136 100644
--- a/Billing.Shared/Helper.cs
+++ b/Billing.Shared/Helper.cs
@@ -39,6 +39,7 @@ namespace Billing
 
         public static void Error(string category, Exception ex)
         {
+            MainThread.BeginInvokeOnMainThread(async () => await Shell.Current.DisplayAlert(category, ex.ToString(), "Ok"));
         }
 
         public static void Error(string category, string message)
@@ -139,15 +140,10 @@ namespace Billing
         public delegate void PropertyValueChanged<TResult, TOwner>(TOwner obj, TResult old, TResult @new);
     }
 
-    internal class AsyncLazy<T>
+    public class AsyncLazy<T>
     {
         private readonly Lazy<Task<T>> instance;
 
-        public AsyncLazy(Func<T> factory)
-        {
-            instance = new Lazy<Task<T>>(() => Task.Run(factory));
-        }
-
         public AsyncLazy(Func<Task<T>> factory)
         {
             instance = new Lazy<Task<T>>(() => Task.Run(factory));
diff --git a/Billing.Shared/Store/StoreHelper.cs b/Billing.Shared/Store/StoreHelper.cs
index 2ad5562..a864f65 100644
--- a/Billing.Shared/Store/StoreHelper.cs
+++ b/Billing.Shared/Store/StoreHelper.cs
@@ -28,68 +28,97 @@ namespace Billing.Store
             {
                 return false;
             }
-            if (database != null)
+            try
             {
-                await database.CloseAsync();
+                if (database != null)
+                {
+                    await database.CloseAsync();
+                }
+            }
+            catch (Exception ex)
+            {
+                Helper.Error("database.close", ex);
+            }
+            try
+            {
+                File.Copy(file, path, true);
+            }
+            catch (Exception ex)
+            {
+                Helper.Error("file.import", ex);
+            }
+            try
+            {
+                database = new SQLiteAsyncConnection(path,
+                    SQLiteOpenFlags.ReadWrite |
+                    SQLiteOpenFlags.Create |
+                    SQLiteOpenFlags.SharedCache);
+            }
+            catch (Exception ex)
+            {
+                Helper.Error("database.connect", ex);
             }
-            File.Copy(file, path, true);
-            database = new SQLiteAsyncConnection(path,
-                SQLiteOpenFlags.ReadWrite |
-                SQLiteOpenFlags.Create |
-                SQLiteOpenFlags.SharedCache);
             return true;
         }
 
-        private static readonly AsyncLazy<StoreHelper> Instance = new(async () =>
+        public static readonly AsyncLazy<StoreHelper> Instance = new(async () =>
         {
             var instance = new StoreHelper();
-            await database.CreateTablesAsync<Category, Account, Bill>();
-            var count = await database.ExecuteScalarAsync<int>("SELECT COUNT(Id) FROM [Category]");
-            if (count <= 0)
+            try
             {
-                // init categories
-                await database.InsertAllAsync(new List<Category>
+                await database.CreateTablesAsync<Category, Account, Bill>();
+            } catch (Exception ex)
+            {
+                Helper.Error("database.init.table", ex);
+            }
+            try
+            {
+                var count = await database.ExecuteScalarAsync<int>("SELECT COUNT(Id) FROM [Category]");
+                if (count <= 0)
                 {
-                    // sample categories
-                    new() { Name = Resource.Clothing, Icon = "clothes" },
-                    new() { Name = Resource.Food, Icon = "food" },
-                    new() { Name = Resource.Daily, Icon = "daily" },
-                    new() { Name = Resource.Trans, Icon = "trans" },
-                    new() { Name = Resource.Entertainment, Icon = "face" },
-                    new() { Name = Resource.Learn, Icon = "learn" },
-                    new() { Name = Resource.Medical, Icon = "medical" },
-                    new() { Name = Resource.OtherSpending, Icon = "plus" },
+                    // init categories
+                    await database.InsertAllAsync(new List<Category>
+                    {
+                        // sample categories
+                        new() { Name = Resource.Clothing, Icon = "clothes" },
+                        new() { Name = Resource.Food, Icon = "food" },
+                        new() { Name = Resource.Daily, Icon = "daily" },
+                        new() { Name = Resource.Trans, Icon = "trans" },
+                        new() { Name = Resource.Entertainment, Icon = "face" },
+                        new() { Name = Resource.Learn, Icon = "learn" },
+                        new() { Name = Resource.Medical, Icon = "medical" },
+                        new() { Name = Resource.OtherSpending, Icon = "plus" },
 
-                    new() { Type = CategoryType.Income, Name = Resource.Earnings, Icon = "#brand#btc" },
-                    new() { Type = CategoryType.Income, Name = Resource.OtherIncome, Icon = "plus" },
+                        new() { Type = CategoryType.Income, Name = Resource.Earnings, Icon = "#brand#btc" },
+                        new() { Type = CategoryType.Income, Name = Resource.OtherIncome, Icon = "plus" },
 
-                    // sub-categories
-                    new() { ParentId = 1, Name = Resource.Jewellery, Icon = "gem" },
-                    new() { ParentId = 1, Name = Resource.Cosmetics, Icon = "makeup" },
-                    new() { ParentId = 2, Name = Resource.Brunch, Icon = "brunch" },
-                    new() { ParentId = 2, Name = Resource.Dinner, Icon = "dinner" },
-                    new() { ParentId = 2, Name = Resource.Drinks, Icon = "drink" },
-                    new() { ParentId = 2, Name = Resource.Fruit, Icon = "fruit" },
-                    new() { ParentId = 3, Name = Resource.UtilityBill, Icon = "bill" },
-                    new() { ParentId = 3, Name = Resource.PropertyFee, Icon = "fee" },
-                    new() { ParentId = 3, Name = Resource.Rent, Icon = "rent" },
-                    new() { ParentId = 3, Name = Resource.Maintenance, Icon = "maintenance" },
-                    new() { ParentId = 4, Name = Resource.LightRail, Icon = "rail" },
-                    new() { ParentId = 4, Name = Resource.Taxi, Icon = "taxi" },
-                    new() { ParentId = 5, Name = Resource.Fitness, Icon = "fitness" },
-                    new() { ParentId = 5, Name = Resource.Party, Icon = "party" },
-                    new() { ParentId = 9, Type = CategoryType.Income, Name = Resource.Salary, Icon = "#brand#buffer" },
-                    new() { ParentId = 9, Type = CategoryType.Income, Name = Resource.Bonus, Icon = "dollar" },
-                });
+                        // sub-categories
+                        new() { ParentId = 1, Name = Resource.Jewellery, Icon = "gem" },
+                        new() { ParentId = 1, Name = Resource.Cosmetics, Icon = "makeup" },
+                        new() { ParentId = 2, Name = Resource.Brunch, Icon = "brunch" },
+                        new() { ParentId = 2, Name = Resource.Dinner, Icon = "dinner" },
+                        new() { ParentId = 2, Name = Resource.Drinks, Icon = "drink" },
+                        new() { ParentId = 2, Name = Resource.Fruit, Icon = "fruit" },
+                        new() { ParentId = 3, Name = Resource.UtilityBill, Icon = "bill" },
+                        new() { ParentId = 3, Name = Resource.PropertyFee, Icon = "fee" },
+                        new() { ParentId = 3, Name = Resource.Rent, Icon = "rent" },
+                        new() { ParentId = 3, Name = Resource.Maintenance, Icon = "maintenance" },
+                        new() { ParentId = 4, Name = Resource.LightRail, Icon = "rail" },
+                        new() { ParentId = 4, Name = Resource.Taxi, Icon = "taxi" },
+                        new() { ParentId = 5, Name = Resource.Fitness, Icon = "fitness" },
+                        new() { ParentId = 5, Name = Resource.Party, Icon = "party" },
+                        new() { ParentId = 9, Type = CategoryType.Income, Name = Resource.Salary, Icon = "#brand#buffer" },
+                        new() { ParentId = 9, Type = CategoryType.Income, Name = Resource.Bonus, Icon = "dollar" },
+                    });
+                }
+            }
+            catch (Exception ex)
+            {
+                Helper.Error("database.init.category", ex);
             }
             return instance;
         });
 
-        public static async Task<List<Account>> GetAccountsAsync()
-        {
-            var instance = await Instance;
-            return await instance.GetListAsync<Account>();
-        }
         public static async Task<int> SaveAccountItemAsync(Account account)
         {
             var instance = await Instance;
@@ -101,11 +130,6 @@ namespace Billing.Store
             return await instance.DeleteItemAsync(account);
         }
 
-        public static async Task<List<Bill>> GetBillsAsync()
-        {
-            var instance = await Instance;
-            return await instance.GetListAsync<Bill>();
-        }
         public static async Task<int> SaveBillItemAsync(Bill bill)
         {
             var instance = await Instance;
@@ -117,11 +141,6 @@ namespace Billing.Store
             return await instance.DeleteItemAsync(bill);
         }
 
-        public static async Task<List<Category>> GetCategoriesAsync()
-        {
-            var instance = await Instance;
-            return await instance.GetListAsync<Category>();
-        }
         public static async Task<int> SaveCategoryItemAsync(Category category)
         {
             var instance = await Instance;
@@ -137,10 +156,17 @@ namespace Billing.Store
         {
             if (database == null)
             {
-                database = new SQLiteAsyncConnection(DatabasePath,
-                    SQLiteOpenFlags.ReadWrite |
-                    SQLiteOpenFlags.Create |
-                    SQLiteOpenFlags.SharedCache);
+                try
+                {
+                    database = new SQLiteAsyncConnection(DatabasePath,
+                        SQLiteOpenFlags.ReadWrite |
+                        SQLiteOpenFlags.Create |
+                        SQLiteOpenFlags.SharedCache);
+                }
+                catch (Exception ex)
+                {
+                    Helper.Error("database.ctor.connect", ex);
+                }
             }
         }
 
@@ -178,7 +204,7 @@ namespace Billing.Store
 
         #region Helper
 
-        private Task<List<T>> GetListAsync<T>() where T : new()
+        public Task<List<T>> GetListAsync<T>() where T : new()
         {
             try
             {
@@ -191,7 +217,7 @@ namespace Billing.Store
             return default;
         }
 
-        private Task<int> SaveItemAsync<T>(T item) where T : IIdItem
+        public Task<int> SaveItemAsync<T>(T item) where T : IIdItem
         {
             try
             {
@@ -211,7 +237,7 @@ namespace Billing.Store
             return Task.FromResult(0);
         }
 
-        private Task<int> DeleteItemAsync<T>(T item) where T : IIdItem
+        public Task<int> DeleteItemAsync<T>(T item) where T : IIdItem
         {
             try
             {
diff --git a/Billing/Billing.Android/Billing.Android.csproj b/Billing/Billing.Android/Billing.Android.csproj
index 83f151f..f7c92e0 100644
--- a/Billing/Billing.Android/Billing.Android.csproj
+++ b/Billing/Billing.Android/Billing.Android.csproj
@@ -60,7 +60,6 @@
     <Reference Include="System" />
     <Reference Include="System.Core" />
     <Reference Include="System.Numerics" />
-    <Reference Include="System.Numerics.Vectors" />
     <Reference Include="System.Xml.Linq" />
     <Reference Include="System.Xml" />
   </ItemGroup>
diff --git a/Billing/Billing.Android/Properties/AndroidManifest.xml b/Billing/Billing.Android/Properties/AndroidManifest.xml
index c1fd536..94742bc 100644
--- a/Billing/Billing.Android/Properties/AndroidManifest.xml
+++ b/Billing/Billing.Android/Properties/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="0.10.311" package="org.tsanie.billing" android:installLocation="auto" android:versionCode="10">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0.312" package="org.tsanie.billing" android:installLocation="auto" android:versionCode="11">
 	<uses-sdk android:minSdkVersion="24" android:targetSdkVersion="30" />
 	<application android:label="@string/applabel" android:theme="@style/MainTheme"></application>
 	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
diff --git a/Billing/Billing.iOS/Billing.iOS.csproj b/Billing/Billing.iOS/Billing.iOS.csproj
index 97d5b5f..12e621d 100644
--- a/Billing/Billing.iOS/Billing.iOS.csproj
+++ b/Billing/Billing.iOS/Billing.iOS.csproj
@@ -38,6 +38,7 @@
     <MtouchLink>None</MtouchLink>
     <MtouchArch>x86_64</MtouchArch>
     <CodesignKey>iPhone Distribution</CodesignKey>
+    <MtouchUseLlvm>true</MtouchUseLlvm>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
     <DebugSymbols>true</DebugSymbols>
@@ -64,6 +65,8 @@
     <CodesignKey>iPhone Distribution</CodesignKey>
     <CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
     <MtouchLink>SdkOnly</MtouchLink>
+    <MtouchInterpreter>-all</MtouchInterpreter>
+    <MtouchUseLlvm>true</MtouchUseLlvm>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="Definition.cs" />
@@ -166,14 +169,13 @@
     <Reference Include="System.Xml.Linq" />
     <Reference Include="Xamarin.iOS" />
     <Reference Include="System.Numerics" />
-    <Reference Include="System.Numerics.Vectors" />
   </ItemGroup>
   <ItemGroup>
     <PackageReference Include="Microcharts.Forms" Version="0.9.5.9" />
     <PackageReference Include="SkiaSharp.Views.Forms" Version="2.80.3" />
+    <PackageReference Include="sqlite-net-pcl" Version="1.8.116" />
     <PackageReference Include="Xamarin.Forms" Version="5.0.0.2337" />
     <PackageReference Include="Xamarin.Essentials" Version="1.7.1" />
-    <PackageReference Include="sqlite-net-pcl" Version="1.8.116" />
   </ItemGroup>
   <ItemGroup>
     <BundleResource Include="Resources\dollar.png" />
@@ -477,14 +479,6 @@
   <ItemGroup>
     <BundleResource Include="Resources\left%403x.png" />
   </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\..\Billing.ShareExtension\Billing.ShareExtension.csproj">
-      <IsAppExtension>true</IsAppExtension>
-      <Project>{D4EA6D3A-17E6-4300-80A7-2ED19B738C6B}</Project>
-      <Name>Billing.ShareExtension</Name>
-      <ReferenceSourceTarget></ReferenceSourceTarget>
-    </ProjectReference>
-  </ItemGroup>
   <Import Project="..\..\Billing.Shared\Billing.Shared.projitems" Label="Shared" />
   <Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
 </Project>
\ No newline at end of file
diff --git a/Billing/Billing.iOS/Info.plist b/Billing/Billing.iOS/Info.plist
index 2d44104..6fc8414 100644
--- a/Billing/Billing.iOS/Info.plist
+++ b/Billing/Billing.iOS/Info.plist
@@ -42,23 +42,23 @@
 		<string>OpenSans-SemiBold.ttf</string>
 	</array>
 	<key>CFBundleDocumentTypes</key>
- 	<array>
- 		<dict>
- 			<key>CFBundleTypeName</key>
- 			<string>Master SQLite file</string>
- 			<key>LSItemContentTypes</key>
- 			<array>
- 				<string>public.data</string>
- 			</array>
- 			<key>CFBundleTypeIconFiles</key>
- 			<array>
- 				<string>Assets.xcassets/AppIcon.appiconset/Icon180</string>
- 			</array>
- 		</dict>
- 	</array>
+	<array>
+		<dict>
+			<key>CFBundleTypeName</key>
+			<string>Master SQLite file</string>
+			<key>LSItemContentTypes</key>
+			<array>
+				<string>public.data</string>
+			</array>
+			<key>CFBundleTypeIconFiles</key>
+			<array>
+				<string>Assets.xcassets/AppIcon.appiconset/Icon180</string>
+			</array>
+		</dict>
+	</array>
 	<key>CFBundleVersion</key>
-	<string>10</string>
+	<string>11</string>
 	<key>CFBundleShortVersionString</key>
-	<string>0.10.311</string>
+	<string>1.0.312</string>
 </dict>
 </plist>