You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
custom_summary = "Deep-Linking unlocked on iOS with Bevy"
7
+
hidden=true
8
+
+++
9
+
10
+
Until very recently Bevy iOS apps had a hard time reading deep linking information. Bevy uses [winit](https://github.com/rust-windowing/winit) by default for its platform integrations like window lifecycle management. On iOS winit used to implement and register its own `AppDelegate` to receive app life cycle hooks/calls.
11
+
12
+
Users of Bevy therefore had only one inconvenient options to receive these hooks: Ditch winit and roll this themselves.
13
+
14
+
As of `winit 0.30.10` ([see release](https://github.com/rust-windowing/winit/releases/tag/v0.30.10)) we can now do much better.
15
+
16
+
# What is the use case?
17
+
18
+
"Deep linking" means that a link leads to our app being opened or foregrounded and the app knowing *that* and *what* url triggered it. The iOS jargon for this is [URL Scheme](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app). Some example use cases for this are:
19
+
20
+
* Sharing specific content inside the app (imagine a user sharing their game profile with a friend)
> You might wonder why this is relevant for File-Sharing on iOS. It turns out that the code that triggers your app to open after sharing a file with it is actually just using such a URL scheme to do that.
25
+
26
+
# High level steps
27
+
28
+
1. Configure your url schema in xcode
29
+
2. Add a handler for the `application:(_:open:options:)` call. ([see docs](https://developer.apple.com/documentation/UIKit/UIApplicationDelegate/application(_:open:options:)))
30
+
3. Handle deep link properly
31
+
32
+
## Configure your url schema
33
+
34
+
For iOS to open your app on a click on a specifically crafted URL we have to adapt our `Info.plist` file like so:
35
+
36
+
```xml
37
+
...
38
+
<key>CFBundleURLTypes</key>
39
+
<array>
40
+
<dict>
41
+
<key>CFBundleURLName</key>
42
+
<string>com.rustunit.tinytakeoff</string>
43
+
<key>CFBundleURLSchemes</key>
44
+
<array>
45
+
<string>tinytakeoff</string>
46
+
</array>
47
+
</dict>
48
+
</array>
49
+
```
50
+
51
+
With this our game [tinytakeoff](https://tinytakeoff.com) will be opened when clicking on URL looking this: `tinytakeoff://fooobar?param=value`
52
+
53
+
Alternatively you can also make that change via the XCode UI, see the [docs to register your URL scheme](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app#Register-your-URL-scheme).
54
+
55
+
So far these steps were possible already before and lead to your app being opened or foregrounded based on a click on such a URL.
56
+
57
+
What was not possible was step 2 and 3 to actually make use of that information inside your Bevy app.
58
+
59
+
## Receive app open options
60
+
61
+
Thanks to the [objc2](https://github.com/madsmtm/objc2) crate we can use native objc APIs without having to write objc but pure rust instead. The underlying code looks like magic and uses a bunch of macros to accomplish this. The result is that we can abstract this away into a conventient rust only crate: [bevy_ios_app_delegate](https://github.com/rustunit/bevy_ios_app_delegate).
62
+
63
+
Using this crate hooking into this open url life cycle call of the `AppDelegate` becomes as easy as this snippet of bevy setup code:
64
+
65
+
```rust
66
+
pubfnplugin(app:&mutApp) {
67
+
// bevy setup skipped here...
68
+
69
+
// register our crates plugin (this is a noop on non ios platforms)
70
+
app.add_plugins(IosAppDelegatePlugin);
71
+
72
+
// register observer that triggers if open url app delegate was called (either by app opening or forgrounding after a click on a URL scheme)
This is of course very application dependant. Here are a few example of what to do:
82
+
83
+
| Link action | App behaviour |
84
+
| --- | --- |
85
+
| game user profile link | App opens the user profile of the user that created the link |
86
+
| a players new record game run | The app shows this players replay after clicking their link |
87
+
| file sharing | A `ShareExtension` receives a file that it wants to share with your app and opens your app using a URL schema and the app can identify what file to open using the deep linking context |
88
+
89
+
# Further steps
90
+
91
+
**universal links**
92
+
93
+
Aside from the custom URL schema we described above a regular web domain can be associated with your app and trigger opening it, this is called *universal linking* ([see apple docs](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app)) and requires yet another `AppDelegate`[call implementation](https://developer.apple.com/documentation/appkit/nsapplicationdelegate/application(_:continue:restorationhandler:)).
94
+
95
+
**push notification token**
96
+
97
+
Being able to make a custom `AppDelegate` implementation has more advantage than just for deep linking. We can now vastly simplify also the way we currently receive a push notification token in the [bevy_ios_notifications](https://github.com/rustunit/bevy_ios_notifications) crate. Receiving this token also happens via `AppDelegate` call and will be provided via the new `bevy_ios_app_delegate` crate soon.
98
+
99
+
Exciting times to build iOS apps using Bevy.
100
+
101
+
---
102
+
103
+
Do you need support building your Bevy or Rust project? Our team of experts can support you! [Contact us.](@/contact.md)
<metaname="description" content="Rustunit offers software development consulting with a focus on rust, game-development and large scale distributed backend services.">
<p>Until very recently Bevy iOS apps had a hard time reading deep linking information. Bevy uses <ahref="https://github.com/rust-windowing/winit">winit</a> by default for its platform integrations like window lifecycle management. On iOS winit used to implement and register its own <code>AppDelegate</code> to receive app life cycle hooks/calls.</p>
35
+
<p>Users of Bevy therefore had only one inconvenient options to receive these hooks: Ditch winit and roll this themselves.</p>
36
+
<p>As of <code>winit 0.30.10</code> (<ahref="https://github.com/rust-windowing/winit/releases/tag/v0.30.10">see release</a>) we can now do much better.</p>
37
+
<h1id="what-is-the-use-case">What is the use case?</h1>
38
+
<p>"Deep linking" means that a link leads to our app being opened or foregrounded and the app knowing <em>that</em> and <em>what</em> url triggered it. The iOS jargon for this is <ahref="https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app">URL Scheme</a>. Some example use cases for this are:</p>
39
+
<ul>
40
+
<li>Sharing specific content inside the app (imagine a user sharing their game profile with a friend)</li>
<p>You might wonder why this is relevant for File-Sharing on iOS. It turns out that the code that triggers your app to open after sharing a file with it is actually just using such a URL scheme to do that.</p>
46
+
</blockquote>
47
+
<h1id="high-level-steps">High level steps</h1>
48
+
<ol>
49
+
<li>Configure your url schema in xcode</li>
50
+
<li>Add a handler for the <code>application:(_:open:options:)</code> call. (<ahref="https://developer.apple.com/documentation/UIKit/UIApplicationDelegate/application(_:open:options:)">see docs</a>)</li>
51
+
<li>Handle deep link properly</li>
52
+
</ol>
53
+
<h2id="configure-your-url-schema">Configure your url schema</h2>
54
+
<p>For iOS to open your app on a click on a specifically crafted URL we have to adapt our <code>Info.plist</code> file like so:</p>
<p>With this our game <ahref="https://tinytakeoff.com">tinytakeoff</a> will be opened when clicking on URL looking this: <code>tinytakeoff://fooobar?param=value</code></p>
69
+
<p>Alternatively you can also make that change via the XCode UI, see the <ahref="https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app#Register-your-URL-scheme">docs to register your URL scheme</a>.</p>
70
+
<p>So far these steps were possible already before and lead to your app being opened or foregrounded based on a click on such a URL.</p>
71
+
<p>What was not possible was step 2 and 3 to actually make use of that information inside your Bevy app.</p>
72
+
<h2id="receive-app-open-options">Receive app open options</h2>
73
+
<p>Thanks to the <ahref="https://github.com/madsmtm/objc2">objc2</a> crate we can use native objc APIs without having to write objc but pure rust instead. The underlying code looks like magic and uses a bunch of macros to accomplish this. The result is that we can abstract this away into a conventient rust only crate: <ahref="https://github.com/rustunit/bevy_ios_app_delegate">bevy_ios_app_delegate</a>.</p>
74
+
<p>Using this crate hooking into this open url life cycle call of the <code>AppDelegate</code> becomes as easy as this snippet of bevy setup code:</p>
</span><span></span><spanstyle="font-style:italic;color:#4a4a4a;">// register observer that triggers if open url app delegate was called (either by app opening or forgrounding after a click on a URL scheme)
<tr><td>game user profile link</td><td>App opens the user profile of the user that created the link</td></tr>
91
+
<tr><td>a players new record game run</td><td>The app shows this players replay after clicking their link</td></tr>
92
+
<tr><td>file sharing</td><td>A <code>ShareExtension</code> receives a file that it wants to share with your app and opens your app using a URL schema and the app can identify what file to open using the deep linking context</td></tr>
93
+
</tbody></table>
94
+
<h1id="further-steps">Further steps</h1>
95
+
<p><strong>universal links</strong></p>
96
+
<p>Aside from the custom URL schema we described above a regular web domain can be associated with your app and trigger opening it, this is called <em>universal linking</em> (<ahref="https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app">see apple docs</a>) and requires yet another <code>AppDelegate</code><ahref="https://developer.apple.com/documentation/appkit/nsapplicationdelegate/application(_:continue:restorationhandler:)">call implementation</a>.</p>
97
+
<p><strong>push notification token</strong></p>
98
+
<p>Being able to make a custom <code>AppDelegate</code> implementation has more advantage than just for deep linking. We can now vastly simplify also the way we currently receive a push notification token in the <ahref="https://github.com/rustunit/bevy_ios_notifications">bevy_ios_notifications</a> crate. Receiving this token also happens via <code>AppDelegate</code> call and will be provided via the new <code>bevy_ios_app_delegate</code> crate soon.</p>
99
+
<p>Exciting times to build iOS apps using Bevy.</p>
100
+
<hr/>
101
+
<p>Do you need support building your Bevy or Rust project? Our team of experts can support you! <ahref="https://rustunit.com/contact/">Contact us.</a></p>
0 commit comments