[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"navigation":3,"url-settings":86,"blog-\u002Fblog\u002Fdeep-linking-with-flutter-for-macos":663,"blog-author-\u002Fblog\u002Fdeep-linking-with-flutter-for-macos":1268,"i-material-symbols:arrow-back-rounded":1282},{"id":4,"extension":5,"footer":6,"header":73,"meta":83,"stem":84,"__hash__":85},"navigation\u002Fdata\u002Fshared\u002Fnavigation.yml","yml",{"brand":7,"columns":13,"legal":63},{"name":8,"tagline":9,"downloadCta":10},"Pieces","The memory layer for modern work.",{"label":11,"href":12},"All downloads","\u002Fdownloads",[14,26,39,51],{"title":15,"links":16},"Product",[17,20,23],{"label":18,"href":19},"Pieces Desktop","\u002F",{"label":21,"href":22},"Pieces Enterprise","\u002Fenterprise",{"label":24,"href":25},"Pieces MCP","\u002Fmcp",{"title":27,"links":28},"Resources",[29,33,36],{"label":30,"href":31,"external":32},"Documentation","url:docs.home",true,{"label":34,"href":35},"Blog","\u002Fblog",{"label":37,"href":38,"external":32},"GitHub","url:github.org",{"title":40,"links":41},"Community",[42,45,48],{"label":43,"href":44,"external":32},"Discord","url:social.discord",{"label":46,"href":47,"external":32},"X \u002F Twitter","url:social.x",{"label":49,"href":50,"external":32},"LinkedIn","url:social.linkedin",{"title":52,"links":53},"Company",[54,57,60],{"label":55,"href":56},"About","\u002Fabout",{"label":58,"href":59},"Updates","\u002Fupdates",{"label":61,"href":62},"Contact","\u002Fcontact",[64,67,70],{"label":65,"href":66},"Privacy Policy","\u002Flegal\u002Fprivacy",{"label":68,"href":69},"Refund Policy","\u002Flegal\u002Frefund",{"label":71,"href":72},"Terms of Service","\u002Flegal\u002Fterms",{"links":74,"signIn":75,"contact":78,"cta":80},[],{"label":76,"href":77},"Sign in","url:portal.home",{"label":79,"href":62},"Get in touch",{"label":81,"href":82},"Download","url:routes.downloads",{},"data\u002Fshared\u002Fnavigation","VdirGIa8cUm6xLprbBeTKcw914JfyJjWfF-9hSVOX5Y",{"id":87,"extension":5,"links":88,"meta":660,"stem":661,"__hash__":662},"urlSettings\u002Fdata\u002Fshared\u002Furls.yml",[89,93,97,101,105,109,113,117,121,125,129,133,137,141,145,149,153,157,161,165,169,173,177,181,185,189,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252,256,260,264,268,272,276,280,284,288,292,295,299,303,306,310,314,318,322,326,330,334,338,342,346,350,354,358,362,366,370,374,378,382,386,390,394,398,402,406,410,414,418,422,426,430,434,438,442,446,450,453,457,461,465,469,473,477,480,483,486,489,493,497,500,504,508,512,516,520,524,528,532,536,540,544,548,551,555,559,563,567,571,574,577,580,584,587,591,595,599,603,606,610,614,617,620,623,627,631,635,638,641,644,648,652,656],{"key":90,"label":91,"href":92},"downloads.desktop","Desktop download page","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fdownload",{"key":94,"label":95,"href":96},"downloads.macOS.dmgArm64","macOS DMG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fdmg-arm64\u002Fdownload",{"key":98,"label":99,"href":100},"downloads.macOS.dmgIntel","macOS DMG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fdmg\u002Fdownload",{"key":102,"label":103,"href":104},"downloads.macOS.pkg","macOS PKG","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg\u002Fdownload",{"key":106,"label":107,"href":108},"downloads.macOS.universal","Desktop macOS Universal","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fmacos-universal\u002Fdownload",{"key":110,"label":111,"href":112},"downloads.macOS.pkgArm64","Desktop macOS PKG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pfd-arm64\u002Fdownload",{"key":114,"label":115,"href":116},"downloads.macOS.pkgIntel","Desktop macOS PKG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pfd\u002Fdownload",{"key":118,"label":119,"href":120},"downloads.windows.appinstaller","Windows App Installer","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fappinstaller\u002Fpieces_for_x.appinstaller",{"key":122,"label":123,"href":124},"downloads.windows.exe","Windows EXE","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fwindows-exe\u002Fdownload",{"key":126,"label":127,"href":128},"downloads.windows.msix","Windows MSIX","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fwindows-msix\u002Fdownload",{"key":130,"label":131,"href":132},"downloads.windows.suiteManager","Windows Suite Manager","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_suite_windows\u002Fappinstaller\u002Fdownload",{"key":134,"label":135,"href":136},"downloads.linux.flatpakRepo","Linux Flatpak repository","https:\u002F\u002Fbuilds.pieces.app\u002Fpieces-flatpak-repo\u002Fpieces-flatpak.flatpakrepo",{"key":138,"label":139,"href":140},"downloads.linux.snapDesktop","Linux Snap Desktop","https:\u002F\u002Fsnapcraft.io\u002Fpieces-for-developers",{"key":142,"label":143,"href":144},"downloads.linux.snapPiecesOS","Linux Snap PiecesOS","https:\u002F\u002Fsnapcraft.io\u002Fpieces-os",{"key":146,"label":147,"href":148},"downloads.linux.snap","Desktop Linux Snap package","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fsnap\u002Fdownload",{"key":150,"label":151,"href":152},"downloads.piecesOS.macOS.dmgArm64","PiecesOS macOS DMG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fdmg-arm64\u002Fdownload",{"key":154,"label":155,"href":156},"downloads.piecesOS.macOS.dmgIntel","PiecesOS macOS DMG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fdmg\u002Fdownload",{"key":158,"label":159,"href":160},"downloads.piecesOS.macOS.universal","PiecesOS macOS Universal","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fmacos-universal\u002Fdownload",{"key":162,"label":163,"href":164},"downloads.piecesOS.macOS.pkgArm64","PiecesOS macOS PKG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pos-launch-only-arm64\u002Fdownload",{"key":166,"label":167,"href":168},"downloads.piecesOS.macOS.pkgIntel","PiecesOS macOS PKG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pos-launch-only\u002Fdownload",{"key":170,"label":171,"href":172},"downloads.piecesOS.windows.appinstaller","PiecesOS Windows App Installer","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fappinstaller\u002Fos_server.appinstaller",{"key":174,"label":175,"href":176},"downloads.piecesOS.windows.exe","PiecesOS Windows EXE","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fwindows-exe\u002Fdownload",{"key":178,"label":179,"href":180},"downloads.piecesOS.windows.msix","PiecesOS Windows MSIX","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fwindows-msix\u002Fdownload",{"key":182,"label":183,"href":184},"downloads.piecesOS.linux.snap","PiecesOS Linux Snap package","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fsnap\u002Fdownload",{"key":186,"label":187,"href":188},"downloads.combined.macOS.appleSilicon","Combined macOS installer Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-arm64\u002Fdownload",{"key":190,"label":191,"href":104},"downloads.combined.macOS.intel","Combined macOS installer Intel",{"key":193,"label":194,"href":195},"downloads.guides.macOS","macOS installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Fmacos-installation-guide",{"key":197,"label":198,"href":199},"downloads.guides.windows","Windows installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Fwindows-installation-guide",{"key":201,"label":202,"href":203},"downloads.guides.linux","Linux installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide",{"key":205,"label":206,"href":207},"downloads.guides.piecesOS","PiecesOS manual installation","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Fmanual-installation",{"key":209,"label":210,"href":211},"extensions.chrome","Chrome extension","https:\u002F\u002Fchrome.google.com\u002Fwebstore\u002Fdetail\u002Fpieces-save-code-snippets\u002Figbgibhbfonhmjlechmeefimncpekepm",{"key":213,"label":214,"href":215},"extensions.firefox","Firefox add-on","https:\u002F\u002Faddons.mozilla.org\u002Fen-US\u002Ffirefox\u002Faddon\u002Fpieces-save-code-from-the-web\u002F",{"key":217,"label":218,"href":219},"extensions.edge","Edge add-on","https:\u002F\u002Fmicrosoftedge.microsoft.com\u002Faddons\u002Fdetail\u002Fpieces-save-code-snippet\u002Fhglfimcdgonaeeobjckfdabcldfidmim",{"key":221,"label":222,"href":223},"extensions.vscode","VS Code extension","https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=MeshIntelligentTechnologiesInc.pieces-vscode",{"key":225,"label":226,"href":227},"extensions.visualStudio","Visual Studio extension","https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=MeshIntelligentTechnologiesInc.PiecesVisualStudio",{"key":229,"label":230,"href":231},"extensions.jetbrains","JetBrains plugin","https:\u002F\u002Fplugins.jetbrains.com\u002Fplugin\u002F17328-pieces--save-search-share--reuse-code-snippets",{"key":233,"label":234,"href":235},"extensions.obsidian","Obsidian plugin","https:\u002F\u002Fobsidian.md\u002Fplugins?id=pieces-for-developers",{"key":237,"label":238,"href":239},"extensions.sublime","Sublime package","https:\u002F\u002Fpackagecontrol.io\u002Fpackages\u002FPieces",{"key":241,"label":242,"href":243},"extensions.neovim","Neovim plugin","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_neo_vim",{"key":245,"label":246,"href":247},"extensions.jupyterlab","JupyterLab plugin","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fjupyterlab-pieces",{"key":249,"label":250,"href":251},"extensions.cli","Pieces CLI","https:\u002F\u002Fpypi.org\u002Fproject\u002Fpieces-cli\u002F",{"key":253,"label":254,"href":255},"docs.home","Documentation home","https:\u002F\u002Fdocs.pieces.app",{"key":257,"label":258,"href":259},"docs.getStarted","Get started docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces",{"key":261,"label":262,"href":263},"docs.api","API docs","https:\u002F\u002Fdocs.pieces.app\u002Fapi",{"key":265,"label":266,"href":267},"docs.desktop.overview","Desktop overview","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop",{"key":269,"label":270,"href":271},"docs.desktop.onboarding","Desktop onboarding","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fonboarding",{"key":273,"label":274,"href":275},"docs.desktop.timeline","Desktop timeline docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Ftimeline",{"key":277,"label":278,"href":279},"docs.desktop.summaries","Desktop summaries docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fsingle-click-summaries",{"key":281,"label":282,"href":283},"docs.desktop.search","Desktop conversational search docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fconversational-search",{"key":285,"label":286,"href":287},"docs.desktop.drive","Desktop drive docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fdrive",{"key":289,"label":290,"href":291},"docs.desktop.account","Desktop account settings docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fconfiguration\u002Faccount",{"key":293,"label":294,"href":92},"docs.desktop.download","Desktop download docs",{"key":296,"label":297,"href":298},"docs.piecesOS.overview","PiecesOS overview docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies",{"key":300,"label":301,"href":302},"docs.piecesOS.details","PiecesOS details docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os",{"key":304,"label":305,"href":207},"docs.piecesOS.install","PiecesOS install docs",{"key":307,"label":308,"href":309},"docs.piecesOS.quickMenu","PiecesOS quick menu docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Fquick-menu",{"key":311,"label":312,"href":313},"docs.piecesOS.storage","On-device storage docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fon-device-storage",{"key":315,"label":316,"href":317},"docs.piecesOS.troubleshooting","PiecesOS troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Ftroubleshooting",{"key":319,"label":320,"href":321},"docs.mcp.overview","MCP overview docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp",{"key":323,"label":324,"href":325},"docs.mcp.cursor","MCP Cursor docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcursor",{"key":327,"label":328,"href":329},"docs.mcp.vscode","MCP VS Code docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fvs-code",{"key":331,"label":332,"href":333},"docs.mcp.claudeDesktop","MCP Claude Desktop docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-desktop",{"key":335,"label":336,"href":337},"docs.mcp.claudeCode","MCP Claude Code docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-code",{"key":339,"label":340,"href":341},"docs.mcp.claudeCowork","MCP Claude Cowork docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-cowork",{"key":343,"label":344,"href":345},"docs.mcp.githubCopilot","MCP GitHub Copilot docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgithub-copilot",{"key":347,"label":348,"href":349},"docs.mcp.goose","MCP Goose docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgoose",{"key":351,"label":352,"href":353},"docs.mcp.windsurf","MCP Windsurf docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fwindsurf",{"key":355,"label":356,"href":357},"docs.mcp.zed","MCP Zed docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fzed",{"key":359,"label":360,"href":361},"docs.mcp.jetbrains","MCP JetBrains docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fjetbrains-ides",{"key":363,"label":364,"href":365},"docs.mcp.continueDev","MCP Continue docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcontinue-dev",{"key":367,"label":368,"href":369},"docs.mcp.cline","MCP Cline docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcline",{"key":371,"label":372,"href":373},"docs.mcp.raycast","MCP Raycast docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fraycast",{"key":375,"label":376,"href":377},"docs.mcp.rovoDevCli","MCP Rovo Dev CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Frovo-dev-cli",{"key":379,"label":380,"href":381},"docs.mcp.openaiCodexCli","MCP OpenAI Codex CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fopenai-codex-cli",{"key":383,"label":384,"href":385},"docs.mcp.googleGeminiCli","MCP Google Gemini CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgoogle-gemini-cli",{"key":387,"label":388,"href":389},"docs.mcp.amazonQ","MCP Amazon Q docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Famazon-q-developer",{"key":391,"label":392,"href":393},"docs.mcp.chatgptDev","MCP ChatGPT Developer Mode docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fchatgpt-developer-mode",{"key":395,"label":396,"href":397},"docs.mcp.openclaw","MCP OpenClaw docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fopenclaw",{"key":399,"label":400,"href":401},"docs.mcp.mcpRemote","MCP Remote docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fmcp-remote",{"key":403,"label":404,"href":405},"docs.mcp.ngrok","MCP ngrok docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fngrok-setup",{"key":407,"label":408,"href":409},"docs.troubleshooting.macOS","macOS troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Fmacos",{"key":411,"label":412,"href":413},"docs.troubleshooting.windows","Windows troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Fwindows",{"key":415,"label":416,"href":417},"docs.troubleshooting.linux","Linux troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Flinux",{"key":419,"label":420,"href":421},"docs.privacy","Privacy and security docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fprivacy-security-your-data",{"key":423,"label":424,"href":425},"docs.support","Support docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fsupport",{"key":427,"label":428,"href":429},"portal.home","Pieces portal","https:\u002F\u002Fportal.pieces.app",{"key":431,"label":432,"href":433},"site.home","Website home","https:\u002F\u002Fpieces.app",{"key":435,"label":436,"href":437},"site.about","About page","https:\u002F\u002Fpieces.app\u002Fabout",{"key":439,"label":440,"href":441},"site.features","Features page","https:\u002F\u002Fpieces.app\u002Ffeatures",{"key":443,"label":444,"href":445},"site.plugins","Plugins page","https:\u002F\u002Fpieces.app\u002Fplugins",{"key":447,"label":448,"href":449},"site.contact","Contact page","https:\u002F\u002Fpieces.app\u002Fcontact",{"key":451,"label":58,"href":452},"site.updates","https:\u002F\u002Fpieces.app\u002Fupdates",{"key":454,"label":455,"href":456},"site.news","News","https:\u002F\u002Fpieces.app\u002Fnews",{"key":458,"label":459,"href":460},"site.events","Community events","https:\u002F\u002Fpieces.app\u002Fcommunity\u002Fevents",{"key":462,"label":463,"href":464},"site.userStories","User stories","https:\u002F\u002Fpieces.app\u002Fuser-stories",{"key":466,"label":467,"href":468},"site.academy","Academy","https:\u002F\u002Fpieces.app\u002Flearn\u002Facademy",{"key":470,"label":471,"href":472},"site.support","Website support","https:\u002F\u002Fpieces.app\u002Fsupport",{"key":474,"label":475,"href":476},"site.standup","Standup","https:\u002F\u002Fpieces.app\u002Fstandup",{"key":478,"label":34,"href":479},"site.blog","https:\u002F\u002Fcode.pieces.app\u002Fblog",{"key":481,"label":43,"href":482},"social.discord","https:\u002F\u002Fdiscord.gg\u002Fgetpieces",{"key":484,"label":46,"href":485},"social.x","https:\u002F\u002Fx.com\u002Fgetpieces",{"key":487,"label":488,"href":485},"social.twitter","Twitter",{"key":490,"label":491,"href":492},"social.instagram","Instagram","https:\u002F\u002Fwww.instagram.com\u002Fgetpieces\u002F",{"key":494,"label":495,"href":496},"social.tiktok","TikTok","https:\u002F\u002Fwww.tiktok.com\u002F@getpieces",{"key":498,"label":49,"href":499},"social.linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fgetpieces\u002F",{"key":501,"label":502,"href":503},"social.youtube","YouTube","https:\u002F\u002Fyoutube.com\u002F@getpieces",{"key":505,"label":506,"href":507},"github.org","GitHub organization","https:\u002F\u002Fgithub.com\u002Fpieces-app",{"key":509,"label":510,"href":511},"github.support","GitHub support","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport",{"key":513,"label":514,"href":515},"github.issues","GitHub issues","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport\u002Fissues",{"key":517,"label":518,"href":519},"github.discussions","GitHub discussions","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport\u002Fdiscussions",{"key":521,"label":522,"href":523},"github.documentation","GitHub documentation","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fdocumentation",{"key":525,"label":526,"href":527},"github.opensource","GitHub open source","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fopensource",{"key":529,"label":530,"href":531},"github.sdks.python","Python SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-python",{"key":533,"label":534,"href":535},"github.sdks.typescript","TypeScript SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-typescript",{"key":537,"label":538,"href":539},"github.sdks.dart","Dart SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-dart",{"key":541,"label":542,"href":543},"github.sdks.kotlin","Kotlin SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-kotlin",{"key":545,"label":546,"href":547},"github.plugins.obsidian","Obsidian plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fobsidian-pieces",{"key":549,"label":550,"href":247},"github.plugins.jupyterlab","JupyterLab plugin repository",{"key":552,"label":553,"href":554},"github.plugins.sublime","Sublime plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_sublime",{"key":556,"label":557,"href":558},"github.plugins.neovim","Neovim plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_neovim",{"key":560,"label":561,"href":562},"github.cliAgent","CLI agent repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fcli-agent",{"key":564,"label":565,"href":566},"github.mcpDart","MCP Dart repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fmcp_dart",{"key":568,"label":569,"href":570},"github.awesomePieces","Awesome Pieces repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fawesome-pieces",{"key":572,"label":573,"href":66},"legal.privacyPolicy","Privacy policy",{"key":575,"label":576,"href":69},"legal.refundPolicy","Refund policy",{"key":578,"label":579,"href":72},"legal.terms","Terms",{"key":581,"label":582,"href":583},"legal.security","Legal security","https:\u002F\u002Fpieces.app\u002Flegal\u002Fsecurity",{"key":585,"label":586,"href":503},"videos.youtubeChannel","YouTube channel",{"key":588,"label":589,"href":590},"videos.gettingStartedDesktop","Getting started desktop video","https:\u002F\u002Fyoutu.be\u002FdUr1lRM_TYk",{"key":592,"label":593,"href":594},"videos.snippetDiscoveryxR","Snippet discovery video","https:\u002F\u002Fyoutu.be\u002FG6vb1USw-30",{"key":596,"label":597,"href":598},"sales.bookACall","Book a sales call","https:\u002F\u002Fcalendar.app.google\u002FWVUDtUfNy5Vst3sH7",{"key":600,"label":601,"href":602},"sales.enterprise","Enterprise form","https:\u002F\u002Fgetpieces.typeform.com\u002Fto\u002FaVQFTvpE",{"key":604,"label":605,"href":519},"sales.feedback","Feedback discussions",{"key":607,"label":608,"href":609},"sales.earlyAccess","Early access form","https:\u002F\u002Fgetpieces.typeform.com\u002Fearlyaccess",{"key":611,"label":612,"href":613},"sales.supportEmail","Support email","mailto:support@pieces.app",{"key":615,"label":616,"href":19},"routes.home","Home route",{"key":618,"label":619,"href":56},"routes.about","About route",{"key":621,"label":622,"href":12},"routes.downloads","Downloads route",{"key":624,"label":625,"href":626},"routes.thanks","Post-install thanks route","\u002Finstall\u002Fthanks",{"key":628,"label":629,"href":630},"routes.pricing","Pricing route","\u002Fpricing",{"key":632,"label":633,"href":634},"cta.freeTrial","Start free trial CTA (Pieces Pro) — used by \u002Fcampaigns\u002F* landing pages","https:\u002F\u002Fcampaigns.pieces.app\u002F",{"key":636,"label":637,"href":22},"routes.enterprise","Enterprise route",{"key":639,"label":640,"href":62},"routes.contact","Contact route",{"key":642,"label":643,"href":59},"routes.updates","Updates route",{"key":645,"label":646,"href":647},"routes.migrationError","Migration error route","\u002Fmigration\u002Ferror",{"key":649,"label":650,"href":651},"routes.authenticated","Post-login authenticated route","\u002Fauth\u002Fsigned-in",{"key":653,"label":654,"href":655},"routes.signed-out","Signed out route","\u002Fauth\u002Fsigned-out",{"key":657,"label":658,"href":659},"routes.authentication-error","Authentication error route","\u002Fauth\u002Ferror",{},"data\u002Fshared\u002Furls","NLkVE1lIUws518K-1QsSB6T-GvlXYIzcRL1HDhqarGQ",{"id":664,"title":665,"author":666,"authorPhoto":667,"authorPhotoAlt":668,"authorSlug":669,"body":670,"buttonText":1255,"buttonUrl":1256,"category":1257,"date":1258,"description":1259,"draft":1260,"editorsPick":1260,"extension":1261,"featured":1260,"image":1262,"imageAlt":668,"meta":1263,"navigation":32,"ogImage":668,"ogImageAlt":668,"path":1264,"seo":1265,"stem":1266,"tags":668,"__hash__":1267},"blog\u002Fblog\u002Fdeep-linking-with-flutter-for-macos.md","How to set up deep linking with Flutter for macOS apps","Nathan Courtney","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fauthors\u002Fnathan-courtney.png",null,"nathan-courtney",{"type":671,"value":672,"toc":1250},"minimark",[673,677,680,683,688,691,695,706,717,728,735,738,741,747,750,756,767,774,780,783,789,792,795,801,808,815,818,824,827,834,867,870,877,883,889,892,899,914,920,929,953,959,965,968,974,980,987,993,1000,1003,1079,1085,1091,1105,1111,1114,1171,1179,1182,1188,1194,1197,1200,1203,1208,1211,1216,1221,1226,1229,1232,1238,1244,1247],[674,675,676],"p",{},"In today's world, the ability to open desktop applications with specific parameters is a staple feature that any modern application can easily adopt. Setting up this functionality with Flutter on macOS is quite easy without downloading a bloated package or plugin.",[674,678,679],{},"I am Nathan Courtney, Head of DevOps at Pieces.app. I focus on integrating system APIs with Flutter to leverage various features at the operating system level.",[674,681,682],{},"Whether your app is currently running or not, we are going to look into how we can utilize Flutter method channels to create a custom URL scheme or a deep link to launch your macOS application with certain arguments or interact when a user opens the link within their browser.",[684,685,687],"h2",{"id":686},"what-is-deep-linking","What is deep linking?",[674,689,690],{},"A deep link allows your app to be opened from specific URLs, carrying parameters for personalized or contextual interactions. This feature is essential for smooth navigation and enhances user experience.",[684,692,694],{"id":693},"how-to-set-up-deep-linking-for-macos","How to set up deep linking for macOS",[674,696,697,698,705],{},"First, let's start off with a simple Flutter template by ",[699,700,704],"a",{"href":701,"rel":702},"https:\u002F\u002Fpieces.app\u002Fblog\u002Fusing-pieces-flutter-to-build-pieces",[703],"nofollow","creating a new Flutter project"," on macOS:",[707,708,713],"pre",{"className":709,"code":711,"language":712},[710],"language-text","flutter create deep_linking\n","text",[714,715,711],"code",{"__ignoreMap":716},"",[674,718,719,720,723,724,727],{},"Navigate to the new directory you created, ",[714,721,722],{},"\u002Fdeep_linking",",and create a new file and class within our ",[714,725,726],{},"\u002Fdeep_linking\u002Flib","directory.",[674,729,730,731,734],{},"Mine will be ",[714,732,733],{},"\u002Fdeep_linking\u002Flib\u002Fdeep_link_handler.dart",".",[674,736,737],{},"Let’s start by creating a simple class that will be the structure of our query parameters coming in from our URL.",[674,739,740],{},"This doesn’t have to be done, but we can do this to provide more structure to our code if we expect links to arrive in a similar manner and to throw any errors if a link comes in without the proper structure.",[707,742,745],{"className":743,"code":744,"language":712},[710],"class DeepLinkURLParameters {\n  final String id;\n  final String foo;\n  final String bar;\n\n  DeepLinkURLParameters({\n    required this.id,\n    required this.foo,\n    required this.bar,\n  });\n}\n",[714,746,744],{"__ignoreMap":716},[674,748,749],{},"Next, within the same file, let's set up our Flutter method channel, which will handle all the incoming URL parameters that come in from the Swift side.",[707,751,754],{"className":752,"code":753,"language":712},[710],"class DeepLinkHandler {\n  static const MethodChannel channel = MethodChannel('deep_linking\u002Fdeep_link_handler');\n\n  Function(DeepLinkURLParameters)? onReceiveParameters;\n\n  DeepLinkHandler() {\n    DeepLinkHandler.channel.setMethodCallHandler((call) async {\n      switch (call.method.toString()) {\n        case 'urlParams':\n          DeepLinkURLParameters parameters = extractDeepLinkParameters(call.arguments);\n          print(parameters.id);\n          print(parameters.foo);\n          print(parameters.bar);\n          onReceiveParameters?.call(parameters);\n        default:\n          break;\n      }\n      return;\n    });\n  }\n\n  DeepLinkURLParameters extractDeepLinkParameters(Map parameters) {\n    String? id = parameters['id'];\n    String? foo = parameters['foo'];\n    String? bar = parameters['bar'];\n    if (id == null || foo == null || bar == null) {\n      throw Exception('Failed to get all deep-link parameters');\n    }\n\n    return DeepLinkURLParameters(\n      id: id,\n      foo: foo,\n      bar: bar,\n    );\n  }\n}\n",[714,755,753],{"__ignoreMap":716},[674,757,758,759,762,763,766],{},"Our Flutter method channel will listen for messages coming in from the Swift side on the channel: \"",[714,760,761],{},"deep_linking\u002Fdeep_link_handler",".\" We will extract each parameter coming in from Swift as a ",[714,764,765],{},"map"," and print it out to our UI.",[674,768,769,770,773],{},"In your ",[714,771,772],{},"main.dart"," file, we can initialize our class to spin up our method channel and start listening to events coming in from the Swift side:",[707,775,778],{"className":776,"code":777,"language":712},[710],"import 'deep_link_handler.dart';\n\nvoid main() {\n  runApp(const MyApp());\n  WidgetsFlutterBinding.ensureInitialized();\n  DeepLinkHandler();\n}\n",[714,779,777],{"__ignoreMap":716},[674,781,782],{},"We can also modify our application's home page to display our Query Parameters when they start coming in:",[707,784,787],{"className":785,"code":786,"language":712},[710],"class MyApp extends StatelessWidget {\n  const MyApp({super.key});\n\n  \u002F\u002F This widget is the root of your application.\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Deep Link Demo',\n      theme: ThemeData(\n        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),\n        useMaterial3: true,\n      ),\n      home: const MyHomePage(title: 'Deep Link Demo Home Page'),\n    );\n  }\n}\n\nclass MyHomePage extends StatefulWidget {\n  const MyHomePage({super.key, required this.title});\n\n  final String title;\n\n  @override\n  State\u003CMyHomePage> createState() => _MyHomePageState();\n}\n\nclass _MyHomePageState extends State\u003CMyHomePage> {\n  DeepLinkHandler deepLinkHandler = DeepLinkHandler();\n  DeepLinkURLParameters? parameters;\n\n  @override\n  void initState() {\n    super.initState();\n    deepLinkHandler.onReceiveParameters = (DeepLinkURLParameters params) {\n      setState(() {\n        parameters = params;\n      });\n    };\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        backgroundColor: Theme.of(context).colorScheme.inversePrimary,\n        title: Text(widget.title),\n      ),\n      body: Center(\n        child: Column(\n          mainAxisAlignment: MainAxisAlignment.center,\n          children: \u003CWidget>[\n            if (parameters != null) ...[\n              Text('ID: ${parameters!.id}'),\n              Text('Foo: ${parameters!.foo}'),\n              Text('Bar: ${parameters!.bar}'),\n            ] else ...[\n              Text('Waiting for deep link parameters...'),\n            ],\n          ],\n        ),\n      ),\n    );\n  }\n}\n",[714,788,786],{"__ignoreMap":716},[674,790,791],{},"That is it for the Dart side of things, as the rest of the implementation resides within our application's Swift code.",[674,793,794],{},"Let's go ahead and build our Flutter application once, then open it up in Xcode.",[707,796,799],{"className":797,"code":798,"language":712},[710],"flutter build macos\n",[714,800,798],{"__ignoreMap":716},[674,802,803,804,807],{},"Next, let's navigate to our Xcode Project file within ",[714,805,806],{},"\u002Fdeep_linking\u002Fmacos\u002FRunner.xcworkspace"," and double-click it to open it within XCode.",[674,809,810,811,814],{},"First, we will want to navigate to our ",[714,812,813],{},"Info.plist"," to set the URL our app should respond to.",[674,816,817],{},"The easiest way to do this is to right click our Info.plist file and add the following XML code to the document:",[707,819,822],{"className":820,"code":821,"language":712},[710],"   \u003Ckey>CFBundleURLTypes\u003C\u002Fkey>\n    \u003Carray>\n        \u003Cdict>\n            \u003Ckey>CFBundleTypeRole\u003C\u002Fkey>\n            \u003Cstring>Viewer\u003C\u002Fstring>\n            \u003Ckey>CFBundleURLName\u003C\u002Fkey>\n            \u003Cstring>com.example.deepLinking\u003C\u002Fstring>\n            \u003Ckey>CFBundleURLSchemes\u003C\u002Fkey>\n            \u003Carray>\n                \u003Cstring>deep-link-example\u003C\u002Fstring>\n            \u003C\u002Farray>\n        \u003C\u002Fdict>\n    \u003C\u002Farray>\n",[714,823,821],{"__ignoreMap":716},[674,825,826],{},"Let’s break down what some of this does.",[674,828,829,833],{},[830,831,832],"strong",{},"CFBundleURLTypes",": This key holds an array of URL types the app can handle. Each type is defined by a dictionary, which specifies details about how the URL should be processed.",[835,836,837],"ol",{},[838,839,840,841],"li",{},"Inside the dictionary:",[842,843,844,850,856],"ul",{},[838,845,846,849],{},[830,847,848],{},"CFBundleTypeRole",": This field specifies the app's role when handling this URL type. Setting it to \"Viewer\" means the app opens the URL for viewing.",[838,851,852,855],{},[830,853,854],{},"CFBundleURLName",": This is a unique identifier for the URL type. It is set to \"com.example.deepLinking\", which can be any unique string, typically following a reverse-domain style.",[838,857,858,861,862,866],{},[830,859,860],{},"CFBundleURLSchemes",": This key holds an array of URL schemes that the app will recognize. In this case, it's set to ",[863,864,865],"span",{},"\"deep-link-example\"",", meaning your app will respond to URLs that start with deep-link-example:\u002F\u002F.",[674,868,869],{},"With this configuration, macOS will open your app whenever a URL with the deep-link-example:\u002F\u002F scheme is triggered, allowing you to capture parameters from the URL (like those after ?) in your app when launched.",[674,871,872,873,876],{},"Now that our app is set up to handle URLs that start with ",[714,874,875],{},"deep-link-example:\u002F\u002F",", it's time to implement the Swift code to send those URL parameters up to our Dart runtime.",[674,878,879,882],{},[830,880,881],{},"One quick note:"," (and this may not be the case for you) Xcode's inline error detection can sometimes get a little wonky when dealing with Flutter applications. I have found that if you build the Flutter app from within Xcode once, it will properly detect any errors you have within your Swift code. You can see you are having this issue by navigating to MainFlutterWindow.swift in Xcode and see if you get this same error \"No such module 'FlutterMacos\":",[674,884,885],{},[886,887],"img",{"alt":716,"src":888},"https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fdeep-linking-with-flutter-for-macos\u002Fimg-001.png",[674,890,891],{},"If you do see this, simply click the \"Play\" button at the top left to build the application. Your issue should be resolved after the fact. You can then hit the \"Stop\" button to end the application's running.",[674,893,894,895,898],{},"Next, let's create a new Swift file named ",[714,896,897],{},"DeepLinkHandler.swift"," that will handle incoming parameters while our application is running.",[674,900,901,902,905,906,909,910,913],{},"We can then start creating our ",[714,903,904],{},"class"," to set up our Flutter Method Channel on the Swift side, handle Apple Events for our deep linking, and structure our query parameters using a nice ",[714,907,908],{},"Dictionary"," that will conform to a ",[714,911,912],{},"Map"," in Dart.",[707,915,918],{"className":916,"code":917,"language":712},[710],"import Foundation\nimport Cocoa\nimport CoreServices\nimport FlutterMacOS\n\nclass DeepLinkHandler: NSObject, FlutterPlugin {\n    \n    static let shared = DeepLinkHandler();\n    \n    static var channel: FlutterMethodChannel? = nil;\n    \n    public static func register(with registrar: FlutterPluginRegistrar) {\n        DeepLinkHandler.channel = FlutterMethodChannel(\n            name: \"deep_linking\u002Fdeep_link_handler\",\n            binaryMessenger: registrar.messenger)\n        if DeepLinkHandler.channel !== nil {\n            registrar.addMethodCallDelegate(shared, channel: DeepLinkHandler.channel!)\n            print(\"Channel is Registered\");\n        } else {\n            print(\"Channel Is Broken\");\n        }\n    }\n}\n",[714,919,917],{"__ignoreMap":716},[674,921,922,923,925,928],{},"Currently, we are creating a function to register our method channel on “",[714,924,761],{},[830,926,927],{},"”"," and importing some other Swift APIs that we will use later for our Apple Events.",[674,930,931,932,935,936,939,940,943,945,946,949,950,952],{},"An important step we do not want to miss is calling our public ",[714,933,934],{},"register()"," function within our ",[714,937,938],{},"MainFlutterWindow.swift"," to properly link our Flutter Method Channel with the ",[714,941,942],{},"FlutterViewController()",[830,944,734],{}," Doing so will finalize our connection to the Dart runtime and allow our ",[714,947,948],{},"DeepLinkHandler","Dart class to start listening to events captured by our ",[714,951,948],{},"Swift class.",[674,954,955,956,958],{},"Simply add the following line in your ",[714,957,938],{}," file:",[707,960,963],{"className":961,"code":962,"language":712},[710],"DeepLinkHandler.register(with: flutterViewController.registrar(forPlugin: \"DeepLinkHandler\"))\n",[714,964,962],{"__ignoreMap":716},[674,966,967],{},"Your entire file will look something like this:",[707,969,972],{"className":970,"code":971,"language":712},[710],"import Cocoa\nimport FlutterMacOS\n\nclass MainFlutterWindow: NSWindow {\n  override func awakeFromNib() {\n    let flutterViewController = FlutterViewController()\n    let windowFrame = self.frame\n    self.contentViewController = flutterViewController\n    self.setFrame(windowFrame, display: true)\n\n    RegisterGeneratedPlugins(registry: flutterViewController)\n      \n    DeepLinkHandler.register(with: flutterViewController.registrar(forPlugin: \"DeepLinkHandler\"))\n\n    super.awakeFromNib()\n  }\n}\n",[714,973,971],{"__ignoreMap":716},[674,975,976,977,979],{},"Let’s return to our ",[714,978,897],{}," file and create a function to handle incoming Apple Events and a public function that will parse the URL for query parameters and send them to the Dart runtime via the method channel we previously created.",[674,981,982,983,986],{},"Let's start by creating a function to handle Apple Events. We will create ",[714,984,985],{},"handleDeepLinkQuery()"," after the fact.",[707,988,991],{"className":989,"code":990,"language":712},[710],"@objc func handleAppleEvent(event: NSAppleEventDescriptor, replyEvent: NSAppleEventDescriptor) {\n        \n     guard let appleEventDescription = event.paramDescriptor(forKeyword: AEKeyword(keyDirectObject)) else {\n         return\n     }\n        \n     guard let appleEventURLString = appleEventDescription.stringValue else {\n         return\n     }\n        \n        \n     let appleEventURL = URL(string: appleEventURLString)\n     let params = appleEventURL!.query\n        \n     if (params != nil) {\n         if (params?.components(separatedBy: \"&\") != nil) {\n             handleDeepLinkQuery(params: params!)\n         }\n     }  \n }\n",[714,992,990],{"__ignoreMap":716},[674,994,995,996,999],{},"This Swift code defines a function ",[714,997,998],{},"handleAppleEvent"," that is triggered when the app receives an Apple Event.",[674,1001,1002],{},"Here's how it works:",[835,1004,1005,1019,1025,1047],{},[838,1006,1007,1010,1011,1014,1015,1018],{},[830,1008,1009],{},"Extracting the Event Descriptor",": The code attempts to retrieve the main parameter of the Apple Event (commonly the URL string for a deep link) by calling ",[714,1012,1013],{},"paramDescriptor(forKeyword:)"," with the ",[714,1016,1017],{},"keyDirectObject"," keyword.",[838,1020,1021,1024],{},[830,1022,1023],{},"Converting to a String",": If the event descriptor is successfully retrieved, it checks whether it contains a string value, which should be the URL. If either of these steps fails, the function returns early.",[838,1026,1027,1030,1031],{},[830,1028,1029],{},"Creating a URL and Extracting Query Parameters",":",[842,1032,1033,1040],{},[838,1034,1035,1036,1039],{},"If the URL string is valid, the function initializes a ",[714,1037,1038],{},"URL"," object.",[838,1041,1042,1043,1046],{},"It then attempts to get the query part of the URL (everything after ",[714,1044,1045],{},"?","), which contains the parameters.",[838,1048,1049,1030,1052],{},[830,1050,1051],{},"Parsing and Handling Parameters",[842,1053,1054,1069],{},[838,1055,1056,1057,1060,1061,1064,1065,1068],{},"If ",[714,1058,1059],{},"params"," (query string) is not ",[714,1062,1063],{},"nil",", the function separates the parameters by ",[714,1066,1067],{},"&"," (common in query strings to separate key-value pairs).",[838,1070,1071,1072,1075,1076,1078],{},"If parameters exist, it calls ",[714,1073,1074],{},"handleDeepLinkQuery"," with ",[714,1077,1059],{}," to process or handle the parameters further.",[674,1080,1081,1082,1084],{},"Next, let's create a public function ",[714,1083,985],{}," to handle formatting our Query into a nice readable Dictionary that will conform to our Map in dart",[707,1086,1089],{"className":1087,"code":1088,"language":712},[710],"   public func handleDeepLinkQuery(params: String) {\n        let components = params.components(separatedBy: \"&\")\n        \n        var paramDict: [String: String] = [:]\n        \n        for index in 0...2 {\n            paramDict[components[index].components(separatedBy: \"=\")[0]] = components[index].components(separatedBy: \"=\")[1]\n        }\n        \n        if ((paramDict.count == 3) && (paramDict[\"id\"] != nil) && (paramDict[\"foo\"] != nil) && (paramDict[\"bar\"] != nil)) {\n            DeepLinkHandler.channel!.invokeMethod(\"urlParams\", arguments: paramDict)\n        }\n        \n        return\n    }\n",[714,1090,1088],{"__ignoreMap":716},[674,1092,1093,1094,1097,1098,1101,1102,1104],{},"Now, let's add some functions to register and unregister our class with the ",[714,1095,1096],{},"NSAppleEventManger",". In doing so, our macOS app will now accept incoming events. specifically the ",[714,1099,1100],{},"kAEGetURL"," event, fired by the system through the given URL we set in the Info.plist file. This will be triggered when the application is opened via a URL scheme (such as ",[714,1103,875],{},").",[707,1106,1109],{"className":1107,"code":1108,"language":712},[710],"   func registerAppleEventHandler() {\n        NSAppleEventManager.shared().setEventHandler(self, andSelector: #selector(self.handleAppleEvent(event:replyEvent:)), forEventClass: AEEventClass(kInternetEventClass), andEventID: AEEventID(kAEGetURL))\n    }\n    \n    func unregisterAppleEventHandler() {\n        NSAppleEventManager.shared().removeEventHandler(forEventClass: AEEventClass(kInternetEventClass), andEventID: AEEventID(kAEGetURL))\n    }\n",[714,1110,1108],{"__ignoreMap":716},[674,1112,1113],{},"Let’s break down each function:",[835,1115,1116,1166],{},[838,1117,1118,1030,1121],{},[714,1119,1120],{},"registerAppleEventHandler()",[842,1122,1123,1129,1135,1149],{},[838,1124,1125,1126,1128],{},"This function sets up a handler for the ",[714,1127,1100],{}," Apple Event, which is typically triggered when the app is opened via a custom URL scheme.",[838,1130,1131,1134],{},[714,1132,1133],{},"NSAppleEventManager.shared().setEventHandler(...)"," registers self (the current instance of the class) as the handler for this event.",[838,1136,1137,1138,1141,1142,1145,1146,1148],{},"The ",[714,1139,1140],{},"@selector(self.handleAppleEvent(event:replyEvent:))"," specifies that the ",[714,1143,1144],{},"handleAppleEvent(event:replyEvent:)"," method should be called when the ",[714,1147,1100],{}," event occurs.",[838,1150,1137,1151,1154,1155,1158,1159,1162,1163,734],{},[714,1152,1153],{},"forEventClass",": ",[714,1156,1157],{},"AEEventClass(kInternetEventClass)"," and ",[714,1160,1161],{},"andEventID: AEEventID(kAEGetURL)"," arguments specify that this handler should only be triggered for URL events ",[714,1164,1165],{},"(kAEGetURL)",[838,1167,1168,1030],{},[830,1169,1170],{},"unregisterAppleEventHandler()",[842,1172,1173],{},[838,1174,1175,1176,1178],{},"This function removes the event handler for the ",[714,1177,1100],{}," event, effectively stopping the app from handling URL events until the handler is registered again.",[674,1180,1181],{},"We will call these functions on bootup and teardown of our application.",[674,1183,1184,1185,1030],{},"Go ahead and add the following lines of swift in your ",[714,1186,1187],{},"AppDelegate.swift",[707,1189,1192],{"className":1190,"code":1191,"language":712},[710],"override func applicationDidFinishLaunching(_ notification: Notification) {\n    DeepLinkHandler.shared.registerAppleEventHandler()\n}\n    \n    \noverride func applicationWillTerminate(_ notification: Notification) {\n    DeepLinkHandler.shared.unregisterAppleEventHandler()\n}\n",[714,1193,1191],{"__ignoreMap":716},[674,1195,1196],{},"Here’s how it all works: When a URL with the custom scheme is opened, macOS triggers an Apple Event that our Swift code captures, parses, and sends to Flutter over the Method Channel.",[674,1198,1199],{},"Let’s test this all out now!",[674,1201,1202],{},"Run your Flutter application, and attempt to paste the following URL within your browser. Chrome will be an excellent test:",[674,1204,1205],{},[714,1206,1207],{},"deep-link-example:\u002F\u002F?id=123&foo=abc&bar=xyz",[674,1209,1210],{},"If everything is done correctly, you should see those query parameters printed out in the terminal and in the Flutter app's UI.",[674,1212,1213],{},[714,1214,1215],{},"flutter: 123",[674,1217,1218],{},[714,1219,1220],{},"flutter: abc",[674,1222,1223],{},[714,1224,1225],{},"flutter: xyz",[674,1227,1228],{},"But we are not quite done yet! When you build out your production application, you will find that you will not receive any of these values from a cold start.",[674,1230,1231],{},"In this scenario, your application is not currently running in the background.",[674,1233,1234,1235,1237],{},"To fix that, we can add a snippet of code within our ",[714,1236,1187],{}," file to handle this:",[707,1239,1242],{"className":1240,"code":1241,"language":712},[710],"override func application(_ application: NSApplication, open urls: [URL]) {\n     if let url = urls.first {\n         let params = url.query\n         if (params != nil) {\n             if (params?.components(separatedBy: \"&\") != nil) {\n                 DeepLinkHandler.shared.handleDeepLinkQuery(params: params!)\n             }\n         }\n     }\n }\n",[714,1243,1241],{"__ignoreMap":716},[674,1245,1246],{},"Now, when your app isn’t actively running, we can propagate those query params to the Dart runtime on boot! To test this out, you will need to build a release version of your application and then place it within your \u002FApplications directory. You may also need to launch it at least once for everything to register properly.",[674,1248,1249],{},"Now you’re all set and you should be able to flawlessly launch your desktop application through a deeplink, just like this.",{"title":716,"searchDepth":1251,"depth":1251,"links":1252},2,[1253,1254],{"id":686,"depth":1251,"text":687},{"id":693,"depth":1251,"text":694},"Try Pieces for free","https:\u002F\u002Fdocs.pieces.app\u002Finstallation-getting-started\u002Fwhat-am-i-installing","Software Development","2024-11-23T00:00:00.000Z","Learn how to set up deep linking for macOS apps using Flutter in this step-by-step guide. Create seamless navigation experiences, enabling users to access specific content directly within your app.",false,"md","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fdeep-linking-with-flutter-for-macos\u002Fhero.png",{},"\u002Fblog\u002Fdeep-linking-with-flutter-for-macos",{"title":665,"description":1259},"blog\u002Fdeep-linking-with-flutter-for-macos","cLVVLbmMatObrKYc4CXgG0PCM0Mb6PLlHNFRLkEOyrs",{"id":1269,"title":666,"body":1270,"description":1274,"draft":1260,"extension":1261,"meta":1277,"navigation":32,"path":1278,"photo":667,"photoAlt":668,"seo":1279,"stem":1280,"__hash__":1281},"authors\u002Fauthors\u002Fnathan-courtney.md",{"type":671,"value":1271,"toc":1275},[1272],[674,1273,1274],{},"Nathan, Founding Engineer and Head of Developer Operations at Pieces, spends his time making sure deployment is successful across all platforms. He also builds system level integrations as well as other infrastructure related functionality. If you cannot install or update our applications, you know where to point the finger. Outside of his work, he is involved in community theatre and loves to fish.",{"title":716,"searchDepth":1251,"depth":1251,"links":1276},[],{},"\u002Fauthors\u002Fnathan-courtney",{"title":666,"description":1274},"authors\u002Fnathan-courtney","Ebs_pjspo5rSIpBbLiTajvS2sO0rt5ZrTR2bUHGDs4o",{"left":1283,"top":1283,"width":1284,"height":1284,"rotate":1283,"vFlip":1260,"hFlip":1260,"body":1285},0,24,"\u003Cpath fill=\"currentColor\" d=\"m7.825 13l4.9 4.9q.3.3.288.7t-.313.7q-.3.275-.7.288t-.7-.288l-6.6-6.6q-.15-.15-.213-.325T4.426 12t.063-.375t.212-.325l6.6-6.6q.275-.275.688-.275t.712.275q.3.3.3.713t-.3.712L7.825 11H19q.425 0 .713.288T20 12t-.288.713T19 13z\"\u002F>"]