英文:
How to add AppIntent to app target and use it in an interactive widget
问题
如何创建一个在你的应用程序进程中运行的 AppIntent
,并在你的小部件的 Button
中使用它?我创建了一个新文件,将其添加到我的应用程序目标中,创建了我的 AppIntent
结构体,然后在我的小部件中添加了一个按钮:Button(intent: TestIntent()) { Text("Test") }
。这导致了一个编译时错误 Cannot find 'TestIntent' in scope
,这是有道理的,因为这段代码在我尝试使用它的小部件扩展中不存在。但是用于向小部件添加交互性的文档中指出:
> 对于小部件,创建一个新的结构体,采用 AppIntent 协议,并将其添加到您的应用程序目标中... 在协议的必需 perform() 函数中,添加您想要使小部件可用的操作代码。
和
> 如果您采用 AppIntent 协议,可以将您的自定义应用程序意图添加到小部件扩展目标或应用程序目标中。将其添加到应用程序目标中是更好的,因为您可以在应用程序中重复使用您添加到小部件中的按钮或切换。
和
> 当用户与小部件中的按钮或切换进行交互时,系统会在您的应用程序进程中运行 perform() 函数。
英文:
How do you create an AppIntent
that will run in your app's process and use it in your widget's Button
? I created a new file, added it to my app's target, created my AppIntent struct, then added a button to my widget: Button(intent: TestIntent()) { Text("Test") }
. This results in a compile-time error Cannot find 'TestIntent' in scope
which makes sense because this code doesn't exist in the widget extension where I'm trying to use it. But the documentation for adding interactivity to widgets states:
> For a widget, create a new structure that adopts the AppIntent protocol and add it to your app target ... In the protocol’s required perform() function, add code for the action you want to make available to the widget.
and
> If you adopt the AppIntent protocol, you can add your custom app intent to your widget extension target or your app target. Adding it to the app target is preferable because you can then reuse the button or toggle that you add to your widget in your app.
and
> When a person interacts with a button or toggle in your widget, the system runs the perform() function in your app’s process.
答案1
得分: 3
在测试中,我已经能够确定,至少目前为止:
- 如果你不想在你的应用中重用应用程序意图,而只想在交互式小部件中使用它,你可以将你的
AppIntent
结构添加到小部件扩展目标中。使用这种设置,意图将始终在小部件进程中运行。 - 如果你希望你的应用程序意图可以在你的应用和小部件中重用,你可以将你的
AppIntent
结构添加到你的应用和小部件扩展目标中。使用这种设置,如果你的应用正在运行,即使在后台暂停时,意图也将在你的应用进程中运行,在你的应用不在运行时,将在小部件进程中运行。 - 尽管文档所示,似乎不可能创建一个简单的
AppIntent
,它将始终在你的应用进程中运行,除非你实现openAppWhenRun
,这将导致你的应用前台运行,或者你实现不同的意图协议:AudioIntent
、LiveActivityIntent
、ForegroundContinuableIntent
。这些意图类型在后台中在应用程序进程中运行。
我提交了FB12584468以请求更新文档,以解释要求并澄清其工作原理(或修复错误,如果这不是预期行为)。
感谢Mastodon上的Michael澄清了这个行为!"如果你需要强制一个应用程序意图在你的应用中运行,并且它与描述的任何路径都不匹配...我很想了解并了解你的用例。"
英文:
In testing I've been able to determine, at least as of now:
- If you don't want to reuse the app intent in your app, you only want to use it in your interactive widget, you can add your
AppIntent
structure to just the widget extension target. With this setup, the intent will always run in the widget process. - If you want your app intent to be reusable in your app and your widget, you can add your
AppIntent
structure to both your app and widget extension targets. With this setup, the intent will run in your app process if your app is running even if suspended in the background, and in the widget process when your app is not running. - Despite what the documentation implies, it's seemingly not possible to create a simple
AppIntent
that will always run in your app's process, unless you implementopenAppWhenRun
which will cause your app to come to foreground, or you implement a different intent protocol:AudioIntent
,LiveActivityIntent
,ForegroundContinuableIntent
. These intent types run in the app's process in the background.
I submitted FB12584468 to request documentation be updated to explain the requirements and clarify how it works (or fix the bugs if this isn't intended behavior).
And thanks to Michael on Mastodon for clarifying this behavior! "If you need to force an app intent to run in your app and it doesn't match well with any of the paths described ... I’d love to know about it and understand your use case."
答案2
得分: 1
我曾经经历过同样的情况。我猜想这只是Betas版本中的一个bug,因为它似乎与文档相矛盾。
我找到了一个解决方法(截止到Xcode beta 5,iOS 17 beta 4)。如果你实现AudioPlaybackIntent而不是AppIntent,那么它总是在应用程序的进程内启动。
英文:
I was experiencing the same thing. I'm guessing it's just a bug with the Betas, because it does seem to contradict the documentation.
I found a workaround (as of Xcode beta 5, iOS17 beta 4). If you implement AudioPlaybackIntent instead of AppIntent, then it always launches inside the App's process.
答案3
得分: 1
我找到了一个更好的解决方案来交互 Live Activity。
- 您可以创建一个名为 LiveActivityIntent 的结构体,然后将其添加到小部件目标和应用目标中。
- 创建两个文件,一个添加到小部件目标,另一个添加到应用目标,分别扩展您的 Intent 并编写一个相同的函数。小部件目标函数可以为空,应用目标函数是真正的代码。在执行中,在扩展文件中调用您的函数。
以上步骤确保编译成功,当交互意图时,系统将在应用进程中执行您的真正代码。
英文:
I found a better solution for interaction Live Activity.
- You can create a struct impletion LiveActivityIntent then add it to widget target and app target.
- Create two files, one add to widget target, other one add to app target, each extension your Intent and write one same function. Widget target function can empty, app target function is real code. In perform call your function in extensions file.
Above steps make sure compile success and when interaction intent, System will execute your real code in App Process.
答案4
得分: 0
我们可以尝试使用AppIntentsPackage API。
-
创建一个名为MyIntent的框架。
-
定义一个TestIntent。
// MyIntent.framework
public struct TestIntent: AppIntent {
static var title: LocalizedStringResource = "xxx"func perform() async throws -> some IntentResult {
...
return .result()
}
}public struct TestIntents: AppIntentsPackage {}
-
在App或Widget目标中导入MyIntent.framework。
英文:
We can try AppIntentsPackage API
-
create a MyIntent framework
-
define a TestIntent
// MyIntent.framework public struct TestIntent: AppIntent { static var title: LocalizedStringResource = "xxx" func perform() async throws -> some IntentResult { ... return .result() } } public struct TestIntents: AppIntentsPackage {}
-
import the MyIntent.framework in App or Widget Target.
答案5
得分: 0
自版本 15.0 beta 7 起,LiveActivityIntent 正如预期地在主应用程序进程中运行。
英文:
As Version 15.0 beta 7, a LiveActivityIntent runs in the main app process as expected.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论