SKStoreProductViewController必须在模式视图控制器SWIFTUI中使用
我正在为我的SwiftUI应用程序构建一个信息页面。一个项目应打开应用商店,另一个项目应打开邮件。我已经为每个人编写了UIViewControllerRepresentable MailView完全可以正常工作。StoreView显示良好,但按下“取消”按钮时,会引发异常 “***由于未捕获的异常‘SKUnsupportedPresentationException’而终止应用程序,原因是:‘必须在模式视图控制器中使用SKStoreProductViewController’” MailView可以很好地进入didFinish委托方法,但StoreView没有进入didFinish委托方法,它在进入此didFinish方法之前崩溃。请问我做错了什么SKStoreProductViewController必须在模式视图控制器SWIFTUI中使用,swiftui,Swiftui,我正在为我的SwiftUI应用程序构建一个信息页面。一个项目应打开应用商店,另一个项目应打开邮件。我已经为每个人编写了UIViewControllerRepresentable MailView完全可以正常工作。StoreView显示良好,但按下“取消”按钮时,会引发异常 “***由于未捕获的异常‘SKUnsupportedPresentationException’而终止应用程序,原因是:‘必须在模式视图控制器中使用SKStoreProductViewController’” MailView
import SwiftUI
import StoreKit
import MessageUI
struct InfoMoreAppsView: View {
@State var showAppAtStore = false
@State var reportBug = false
@State var result: Result<MFMailComposeResult, Error>? = nil
let otherAppName = "TheoryTest"
var body: some View {
VStack(alignment: .leading){
HStack{
Image(Helper.getOtherAppImageName(otherAppName: otherAppName))
Button(action: { self.showAppAtStore = true }) {
Text(otherAppName)
}
.sheet(isPresented: $showAppAtStore){
StoreView(appID: Helper.getOtherAppID(otherAppName: otherAppName))
}
}
Button(action: { self.reportBug = true }) {
Text("Report a bug")
}
.sheet(isPresented: $reportBug){
MailView(result: self.$result)
}
}
.padding()
.font(.title2)
}
}
struct StoreView: UIViewControllerRepresentable {
let appID: String
@Environment(\.presentationMode) var presentation
class Coordinator: NSObject, SKStoreProductViewControllerDelegate {
@Binding var presentation: PresentationMode
init(presentation: Binding<PresentationMode> ) {
_presentation = presentation
}
private func productViewControllerDidFinish(viewController: SKStoreProductViewController) {
$presentation.wrappedValue.dismiss()
viewController.dismiss(animated: true, completion: nil)
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(presentation: presentation)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<StoreView>) -> SKStoreProductViewController {
let skStoreProductViewController = SKStoreProductViewController()
skStoreProductViewController.delegate = context.coordinator
let parameters = [ SKStoreProductParameterITunesItemIdentifier : appID]
skStoreProductViewController.loadProduct(withParameters: parameters)
return skStoreProductViewController
}
func updateUIViewController(_ uiViewController: SKStoreProductViewController, context: UIViewControllerRepresentableContext<StoreView>) {
}
}
struct MailView: UIViewControllerRepresentable {
@Environment(\.presentationMode) var presentation
@Binding var result: Result<MFMailComposeResult, Error>?
class Coordinator: NSObject, MFMailComposeViewControllerDelegate {
@Binding var presentation: PresentationMode
@Binding var result: Result<MFMailComposeResult, Error>?
init(presentation: Binding<PresentationMode>,
result: Binding<Result<MFMailComposeResult, Error>?>) {
_presentation = presentation
_result = result
}
func mailComposeController(_ controller: MFMailComposeViewController,
didFinishWith result: MFMailComposeResult,
error: Error?) {
defer {
$presentation.wrappedValue.dismiss()
}
guard error == nil else {
self.result = .failure(error!)
return
}
self.result = .success(result)
}
}
func makeCoordinator() -> Coordinator {
return Coordinator(presentation: presentation,
result: $result)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<MailView>) -> MFMailComposeViewController {
let mailComposeViewController = MFMailComposeViewController()
mailComposeViewController.mailComposeDelegate = context.coordinator
mailComposeViewController.setToRecipients([Constants.SUPPORT_EMAIL])
mailComposeViewController.setMessageBody(systemInfo(), isHTML: true)
return mailComposeViewController
}
func systemInfo() -> String {
let device = UIDevice.current
let systemVersion = device.systemVersion
let model = UIDevice.hardwareModel
let mailBody = "Model: " + model + ". OS: " + systemVersion
return mailBody
}
func updateUIViewController(_ uiViewController: MFMailComposeViewController,
context: UIViewControllerRepresentableContext<MailView>) {
}
}
导入快捷键
进口存储套件
导入消息用户界面
结构InfoMoreAppsView:视图{
@状态变量showAppAtStore=false
@State var reportBug=false
@状态变量结果:结果?=nil
让otherAppName=“TheoryTest”
var body:一些观点{
VStack(对齐:。前导){
HStack{
图像(Helper.getOtherAppImageName(otherAppName:otherAppName))
按钮(操作:{self.showAppAtStore=true}){
文本(otherAppName)
}
.表(显示:$showAppAtStore){
StoreView(appID:Helper.getOtherAppID(otherAppName:otherAppName))
}
}
按钮(操作:{self.reportBug=true}){
文本(“报告错误”)
}
.sheet(显示:$reportBug){
MailView(结果:self.$result)
}
}
.padding()
.font(.title2)
}
}
结构StoreView:UIViewControllerRepresentable{
让appID:String
@环境(\.presentationMode)变量表示
类协调器:NSObject,SKStoreProductViewControllerDelegate{
@绑定变量表示:PresentationMode
init(表示:绑定){
_演示文稿=演示文稿
}
私有func ProductViewControllerdFinish(视图控制器:SKStoreProductViewController){
$presentation.wrappedValue.disclose()
viewController.Disclose(动画:true,完成:nil)
}
}
func makeCoordinator()->Coordinator{
退货协调员(演示文稿:演示文稿)
}
func makeUIViewController(上下文:UIViewControllerRepresentableContext)->SKStoreProductViewController{
让skStoreProductViewController=skStoreProductViewController()
skStoreProductViewController.delegate=context.coordinator
let parameters=[SKStoreProductParameteriTunesSiteMidEntifier:appID]
skStoreProductViewController.loadProduct(带参数:参数)
返回skStoreProductViewController
}
func updateUIViewController(uViewController:SKStoreProductViewController,上下文:UIViewControllerRepresentableContext){
}
}
结构MailView:UIViewControllerRepresentable{
@环境(\.presentationMode)变量表示
@绑定变量结果:结果?
类协调器:NSObject,MFMailComposeViewControllerDelegate{
@绑定变量表示:PresentationMode
@绑定变量结果:结果?
初始化(表示:绑定,
结果:有约束力){
_演示文稿=演示文稿
_结果=结果
}
func mailComposeController(u控制器:MFMailComposeViewController,
didFinishWith结果:MFMailComposer结果,
错误:错误?){
推迟{
$presentation.wrappedValue.disclose()
}
保护错误==nil else{
self.result=.failure(错误!)
返回
}
self.result=.success(结果)
}
}
func makeCoordinator()->Coordinator{
返回协调员(演示:演示,
结果:$result)
}
func makeUIViewController(上下文:UIViewControllerRepresentableContext)->MFMailComposeViewController{
让mailComposeViewController=MFMailComposeViewController()
mailComposeViewController.mailComposeDelegate=context.coordinator
mailComposeViewController.setToRecipients([Constants.SUPPORT\u EMAIL])
mailComposeViewController.setMessageBody(systemInfo(),isHTML:true)
返回mailComposeViewController
}
func systemInfo()->字符串{
让设备=UIDevice.current
让systemVersion=device.systemVersion
let model=UIDevice.hardwareModel
让mailBody=“Model:”+Model+“.OS:”+systemVersion
返回邮件体
}
func updateUIViewController(uUIViewController:MFMailComposeViewController,
上下文:UIViewControllerRepresentableContext){
}
}
这不是很“快速”或漂亮,但我没有将SKStoreProductViewController包装在一个可表示的文件中,从而在不崩溃的情况下实现了这一点
struct MovieView: View {
var vc:SKStoreProductViewController = SKStoreProductViewController()
var body: some View {
HStack(){
Button(action: {
let params = [
SKStoreProductParameterITunesItemIdentifier:"1179624268",
SKStoreProductParameterAffiliateToken:"11l4Cu",
SKStoreProductParameterCampaignToken:"hype_movie"
] as [String : Any]
// vc!.delegate = self
vc.loadProduct(withParameters: params, completionBlock: { (success,error) -> Void in
UIApplication.shared.windows.first?.rootViewController?.present(vc, animated: true, completion: nil)
})
}) {
HStack {
Image(systemName: "play.fill")
.font(.headline)
}
.padding(EdgeInsets(top: 6, leading:36, bottom: 6, trailing: 36))
.foregroundColor(.white)
.background(Color(red: 29/255, green: 231/255, blue: 130/255))
.cornerRadius(10)
}
Spacer()
}}