文章目錄
- 1. 要求
- 1.1 無需Apple開發者賬號
- 1.2 最新版mac系統
- 1.3 最新版Xcode
- 2. 配對Mac
- 3. 配置開發證書
- 3.1 創建一個名為MTClient的Xcode項目
- 3.2 找到簽名證書
- 3.3 配置簽名
- 3.4 配置標識符
- 4. 真機調試
- 4.1 設置應用首屏 Launch Screen
- 4.2 設置應用圖標
- 5. 問題
- 5.1 DI異常
- 該問題的解決
- 使用`<UserInterpreter>`
- 探索MAUI
- 曙光
- 5.2 其他報錯
- 5.3 Entitlements權利
1. 要求
1.1 無需Apple開發者賬號
我這里開發的應用僅是用于調試、體驗IOS應用開發流程,并沒有發布到AppSotre的計劃,所以沒有申請一年$99的開發者賬號。
但沒加入開發者計劃也有一些使用限制:
- 你的應用簽名有效期只有一周,到期之后需要重新把手機插到電腦上重新安裝一次。
- 不能分發應用,多臺手機的話只能一個一個裝
(如果你已經有了開發者賬號,則可以參考這篇文章 Maui勸退:用windows直接真機調試iOS,無須和Mac配對,無需mac電腦)
1.2 最新版mac系統
macOS版本:15.0以上。
你需要有一臺裝了macOS的電腦,可以是黑蘋果或白蘋果。(我是找了臺不用的dell電腦,花了50裝了最新的黑果系統)
系統最好是最新版,因為.net 9只支持macOS 15以上的版本。參見:Target Framework
1.3 最新版Xcode
AppStore安裝最新的Xcode,xamarin/maui/avalonia開發的ios應用都依賴xcode。
2. 配對Mac
這一步比較簡單,確保開發機和mac在同一個網段,vs就會自動查找到對應的mac。
然后點擊“connect”即可,會自動在mac上安裝需要的work load,大概需要十幾分鐘。
我這里已經連接過了所以顯示“disconnect”
3. 配置開發證書
總體上可以參考這篇略過時的文章:如何在iPhone或iPad上構建和運行應用程序。
也可以直接參考我的步驟:
3.1 創建一個名為MTClient的Xcode項目
Xcode中首先登錄你的AppleID,然后創建一個名為MTClient的IOS項目。
創建有三個信息比較重要:
- Product Name:這里的MTClient是我應用的名字,你也可以改成其它的。
- Organization Identifier:組織名,你用ApppleID登陸Xcode時會提示是否創建一個組織,這里自動填充的GymOrg就是我之前創建的組織。當然這里也可以用其他的組織。
- Bundle Identifier:核心,牢記,這個相當于你應用的標識符,后續所有的簽名及證書都是基于此標識符。
創建完成后,把手機插到mac上調試下看是否能正常跑起來。
3.2 找到簽名證書
打開SpotLight,輸入KeyChainAccess:
打開鑰匙串訪問.app,搜索關鍵詞develop找到剛創建的證書。
將此證書的名字復制下來備用。
3.3 配置簽名
首先將項目屬性 Bundle Signing Scheme改為Manual Provisioning
:
然后打開項目的.csproj
,添加<CodesignKey>
,值就是之前拷貝的證書字符串。
3.4 配置標識符
簽名配置好了,還要配置對應的應用標識符。簽名+標識符才是完整的一套。
打開info.plist
將Bundle Identifier改為之前我們配置的值即可。
4. 真機調試
這個沒什么好說的,rebuild下項目,然后調試設備選擇你的IOS真機,接下來就是正常的調試步驟。
4.1 設置應用首屏 Launch Screen
默認首屏顯示的是一個白底黑字你應用名字的一個頁面。
你可以修改LaunchScreen.xib
文件內容進行調整:
同樣你可以修改info.plist
的選項以關閉首次打開時顯示首屏頁面:
(但設置為not set后可以影響你app的展示尺寸)
4.2 設置應用圖標
打開info.plist
,在這里設置應用圖標:
需要多個不同寬高的圖標:
可使用在線工具一次性全部生成。
5. 問題
5.1 DI異常
報錯 Attempting to JIT compile method 'Microsoft.Extensions.DependencyInjection.ServiceProvider :
Received unhandled Objective-C exception that was marshalled from a managed exception: Attempting to JIT compile method 'Microsoft.Extensions.DependencyInjection.ServiceProvider Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions:BuildServiceProvider (Microsoft.Extensions.DependencyInjection.IServiceCollection,Microsoft.Extensions.DependencyInjection.ServiceProviderOptions)' while running in aot-only mode. See https://learn.microsoft.com/xamarin/ios/internals/limitations for more information.(System.ExecutionEngineException)at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection )at MessageTransferClient.App.OnFrameworkInitializationCompleted() in H:\MyProgram\SomePractice\Avaloni
此問題只出現在IOS真機上,IOS模擬器、Windows、安卓都沒有問題。原因是因為IOS真機不允許JIT,所以只能用AOT,但并非所有的.net 特性都支持AOT,所以就會報錯。
AOT使用的一些限制具體請參考:Xamarin.iOS 的限制
該問題的解決
使用<UserInterpreter>
但并不意味著所有AOT不支持的特性你都不能使用,可以參考iOS 和 Mac Catalyst 上的 Mono 解釋器官方文檔,在csproj中添加<UseInterpreter>
。這樣對于AOT不支持的特性就可以使用Mono解釋器執行,缺點就是運行速度會慢一點而且也不是100%解決問題。
然而嘗試使用Mono解釋器后并沒有解決此問題,報錯變成了:
Error: VTable setup of type Microsoft.Extensions.DependencyInjection.ServiceProvider failed.
解釋器無法構造出DI類型所需要的函數表,網上搜了一圈也沒找到如何解決。
后續我又嘗試使用SimpleInject等對AOT友好的DI或者自己手寫DI,但我所用到的SignalR.Client這個庫嚴重依賴MSDI,并且無法替換。
探索MAUI
我曾經一度懷疑.net for ios是個雞肋,于是在github上搜索現成的基于SignalR的MAUI開發的app,看是否都能正常工作。搜到一個之后真機調試運行了沒有發現任何問題,DI也完全正常。這難道是Avalonia自身的問題?
于是乎又經歷了一番嘗試:將.net版本改為與MAUI中的一致、將所有用的nuget package改為與MAUI中的一致、檢查plist是否一致,一番操作之后然而并沒有什么用,同樣的報錯。
此問題遂擱置,等周末再研究。
曙光
于是來到了今天上午,在嘗試繼續解決這個問題前,我升級了下VS2022的版本,從17.10升級到了目前的最新版17.14.11。
神奇的是DI就這樣完全好用了,期間一個星期我沒有改動過任何代碼,就這么升級一下VisualStuido就解決了。不確定最終問題原因是出現了VisualStudio里還是依賴的.net9 workload里。
關于JIT問題的兩個參考鏈接:
- https://github.com/AvaloniaUI/Avalonia/discussions/19267
- https://github.com/AvaloniaUI/Avalonia/issues/9934
5.2 其他報錯
開發過程中如果你遇到了像這種奇奇怪怪本不應該報錯的報錯,clean–>rebuild下你的IOS項目就可以了。
5.3 Entitlements權利
在嘗試解決前面的DI問題時,我猜測可能是權利問題(但其實并不是)。所以又檢索了macOS Catalina 公證以及對 .NET 下載和項目的影響這篇文章,了解了下權利。簡單來說所有你準備在IOS或MAC平臺上進行分發的軟件都需要具備對應的權利。
但Avalonia模板創建出來的默認應用,并沒有添加.net對應的權利,所以適時可以將權利添加到Entitlements.plist
文件中。