{"id":5148,"date":"2025-06-25T14:29:41","date_gmt":"2025-06-25T18:29:41","guid":{"rendered":"https:\/\/stepinto.vision\/?p=5148"},"modified":"2026-02-25T10:55:37","modified_gmt":"2026-02-25T15:55:37","slug":"how-to-use-default-launch-behavior","status":"publish","type":"post","link":"https:\/\/stepinto.vision\/example-code\/how-to-use-default-launch-behavior\/","title":{"rendered":"How to use default launch behavior"},"content":{"rendered":"\n<p>This new scene modifier can simplify our apps and reduce the need for Scene Phase.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Overview<\/h2>\n\n\n\n<p>When working with multiple scenes (windows, volumes, spaces) in visionOS we often run into an issue. Say the app has a &#8220;main&#8221; window that can open a secondary window. The user launches the app, uses the main window for a while, then taps a button to open the secondary window. Maybe this is a utility or control panel, or a media viewer. The user closes the main window and when they are done with their task they close the secondary window too. So far so good. But the next time the user taps the app icon, the secondary window shows up. Unless this window has a means to reopen the main window, the user is stuck. The only solution they have is to force quit the app and relaunch it.<\/p>\n\n\n\n<p>In visionOS 1 and 2, we could mitigate issues like this by using Scene Phase to keep track of the state of our scenes. It took some understanding and planning, but it was possible to provide a good user experience.<\/p>\n\n\n\n<p>Starting in visionOS 26 we have a new option. Now we can use a scene modifier called <code><a href=\"https:\/\/developer.apple.com\/documentation\/swiftui\/scene\/defaultlaunchbehavior(_:)\">defaultLaunchBehavior<\/a><\/code>. Take these two windows as an example.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#000000;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#000000;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>struct Garden028App: App {\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n        .defaultSize(width: 500, height: 500)\n\n        WindowGroup(id: \"UtilityWindow\", makeContent: {\n            UtilityRoot()\n        })\n        .defaultLaunchBehavior(.suppressed)\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki light-plus\" style=\"background-color: #FFFFFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #0000FF\">struct<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #267F99\">Garden028App<\/span><span style=\"color: #000000\">: App {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> body: some Scene {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        WindowGroup {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #795E26\">ContentView<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">defaultSize<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">width<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">500<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">height<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">500<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        <\/span><span style=\"color: #795E26\">WindowGroup<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">id<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #A31515\">&quot;UtilityWindow&quot;<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">makeContent<\/span><span style=\"color: #000000\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #795E26\">UtilityRoot<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        })<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">defaultLaunchBehavior<\/span><span style=\"color: #000000\">(.<\/span><span style=\"color: #001080\">suppressed<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>The user opens the main window, then later opens the utility window. They close the main window, then close the utility window. We used <code>.defaultLaunchBehavior(.suppressed)<\/code> on the utility window, so when the user taps on the app icon, visionOS will fallback to the first viable scene it can find. In this case, we only have one other scene, so the app reopens with the main window showing.<\/p>\n\n\n\n<p>This simple scene modifier can save us so many headaches. No longer do we need to juggle scene phase or keep track which windows are open. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Video Demo<\/h2>\n\n\n\n<p>Let&#8217;s see the two scenarios in action.<\/p>\n\n\n\n\t\t<figure class=\"wp-block-jetpack-videopress jetpack-videopress-player\" style=\"\" >\n\t\t\t<div class=\"jetpack-videopress-player__wrapper\"> <div class=\"jetpack-video-wrapper\"><iframe title=\"VideoPress Video Player\" aria-label='VideoPress Video Player' width='720' height='405' src='https:\/\/videopress.com\/embed\/EhNUUEF6?cover=1&amp;autoPlay=0&amp;controls=1&amp;loop=0&amp;muted=0&amp;persistVolume=1&amp;playsinline=0&amp;preloadContent=metadata&amp;useAverageColor=1&amp;hd=0' frameborder='0' allowfullscreen data-resize-to-parent=\"true\" allow='clipboard-write'><\/iframe><script src='https:\/\/v0.wordpress.com\/js\/next\/videopress-iframe.js?m=1739540970'><\/script><\/div><\/div>\n\t\t\t\n\t\t\t\n\t\t<\/figure>\n\t\t<div class=\"wp-video-description\" style=\"margin-top: 10px; margin-bottom: 10px; font-style: italic;\"><p>A video comparison of app launch issues with and without defaultLaunchBehavior<\/p>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\">Example Code<\/h2>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#000000;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#000000;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>struct Garden028App: App {\n    var body: some Scene {\n        WindowGroup {\n            ContentView()\n        }\n        .defaultSize(width: 500, height: 500)\n\n        WindowGroup(id: \"UtilityWindow\", makeContent: {\n            UtilityRoot()\n        })\n        .restorationBehavior(.disabled)\n        .defaultLaunchBehavior(.suppressed)\n        .defaultSize(CGSize(width: 300, height: 200))\n        .defaultWindowPlacement { _, context in\n            if let mainWindow = context.windows.first {\n                return WindowPlacement(.trailing(mainWindow))\n            }\n            return WindowPlacement(.none)\n        }\n\n        ImmersiveSpace(id: \"ImmersiveSpace\") {\n            ImmersiveSpaceRoot()\n        }\n        \/\/ seems to have no effect on immersive spaces\n        \/\/ .defaultLaunchBehavior(.suppressed)\n\n\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki light-plus\" style=\"background-color: #FFFFFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #0000FF\">struct<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #267F99\">Garden028App<\/span><span style=\"color: #000000\">: App {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> body: some Scene {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        WindowGroup {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #795E26\">ContentView<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">defaultSize<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">width<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">500<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">height<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">500<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        <\/span><span style=\"color: #795E26\">WindowGroup<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">id<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #A31515\">&quot;UtilityWindow&quot;<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">makeContent<\/span><span style=\"color: #000000\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #795E26\">UtilityRoot<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        })<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">restorationBehavior<\/span><span style=\"color: #000000\">(.<\/span><span style=\"color: #001080\">disabled<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">defaultLaunchBehavior<\/span><span style=\"color: #000000\">(.<\/span><span style=\"color: #001080\">suppressed<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">defaultSize<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">CGSize<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">width<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">300<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">height<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">200<\/span><span style=\"color: #000000\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #001080\">defaultWindowPlacement<\/span><span style=\"color: #000000\"> { <\/span><span style=\"color: #001080\">_<\/span><span style=\"color: #000000\">, context <\/span><span style=\"color: #AF00DB\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #AF00DB\">if<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #0000FF\">let<\/span><span style=\"color: #000000\"> mainWindow = context.<\/span><span style=\"color: #001080\">windows<\/span><span style=\"color: #000000\">.<\/span><span style=\"color: #795E26\">first<\/span><span style=\"color: #000000\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                <\/span><span style=\"color: #AF00DB\">return<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #795E26\">WindowPlacement<\/span><span style=\"color: #000000\">(.<\/span><span style=\"color: #795E26\">trailing<\/span><span style=\"color: #000000\">(mainWindow))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #AF00DB\">return<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #795E26\">WindowPlacement<\/span><span style=\"color: #000000\">(.<\/span><span style=\"color: #001080\">none<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        <\/span><span style=\"color: #795E26\">ImmersiveSpace<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">id<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #A31515\">&quot;ImmersiveSpace&quot;<\/span><span style=\"color: #000000\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #795E26\">ImmersiveSpaceRoot<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        <\/span><span style=\"color: #008000\">\/\/ seems to have no effect on immersive spaces<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        <\/span><span style=\"color: #008000\">\/\/ .defaultLaunchBehavior(.suppressed)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"has-theme-palette-8-background-color has-background\">Sample code for this post is available in Garden28 in&nbsp;<a href=\"https:\/\/github.com\/radicalappdev\/step-into-examples\">Step Into Examples on GitHub<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This new scene modifier can simplify our apps and reduce the need for Scene Phase.<\/p>\n","protected":false},"author":93705089,"featured_media":5150,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kad_blocks_custom_css":"","_kad_blocks_head_custom_js":"","_kad_blocks_body_custom_js":"","_kad_blocks_footer_custom_js":"","advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"_EventAllDay":false,"_EventTimezone":"","_EventStartDate":"","_EventEndDate":"","_EventStartDateUTC":"","_EventEndDateUTC":"","_EventShowMap":false,"_EventShowMapLink":false,"_EventURL":"","_EventCost":"","_EventCostDescription":"","_EventCurrencySymbol":"","_EventCurrencyCode":"","_EventCurrencyPosition":"","_EventDateTimeSeparator":"","_EventTimeRangeSeparator":"","_EventOrganizerID":[],"_EventVenueID":[],"_OrganizerEmail":"","_OrganizerPhone":"","_OrganizerWebsite":"","_VenueAddress":"","_VenueCity":"","_VenueCountry":"","_VenueProvince":"","_VenueState":"","_VenueZip":"","_VenuePhone":"","_VenueURL":"","_VenueStateProvince":"","_VenueLat":"","_VenueLng":"","_VenueShowMap":false,"_VenueShowMapLink":false,"_kadence_starter_templates_imported_post":false,"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_wpas_customize_per_network":false,"jetpack_post_was_ever_published":false},"categories":[1365],"tags":[],"class_list":["post-5148","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-example-code"],"jetpack_publicize_connections":[],"taxonomy_info":{"category":[{"value":1365,"label":"Example Code"}]},"featured_image_src_large":["https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/06\/step-garden-028-02.jpeg?fit=1024%2C576&ssl=1",1024,576,true],"author_info":{"display_name":"Joseph Simpson","author_link":"https:\/\/stepinto.vision\/author\/vrhermit\/"},"comment_info":0,"category_info":[{"term_id":1365,"name":"Example Code","slug":"example-code","term_group":0,"term_taxonomy_id":11,"taxonomy":"category","description":"Code snippets and examples of using common APIs throughout visionOS development","parent":0,"count":187,"filter":"raw","cat_ID":1365,"category_count":187,"category_description":"Code snippets and examples of using common APIs throughout visionOS development","cat_name":"Example Code","category_nicename":"example-code","category_parent":0}],"tag_info":false,"jetpack_featured_media_url":"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/06\/step-garden-028-02.jpeg?fit=3840%2C2160&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/posts\/5148","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/users\/93705089"}],"replies":[{"embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/comments?post=5148"}],"version-history":[{"count":8,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/posts\/5148\/revisions"}],"predecessor-version":[{"id":8993,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/posts\/5148\/revisions\/8993"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/media\/5150"}],"wp:attachment":[{"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/media?parent=5148"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/categories?post=5148"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/tags?post=5148"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}