8000 GitHub - mutualmobile/MMWormhole: Message passing between iOS apps and extensions.
[go: up one dir, main page]

Skip to content

mutualmobile/MMWormhole

{"props":{"initialPayload":{"allShortcutsEnabled":false,"path":"/","repo":{"id":27653666,"defaultBranch":"master","name":"MMWormhole","ownerLogin":"mutualmobile","currentUserCanPush":false,"isFork":false,"isEmpty":false,"createdAt":"2014-12-07T00:03:44.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/166419?v=4","public":true,"private":false,"isOrgOwned":true},"currentUser":null,"refInfo":{"name":"master","listCacheKey":"v0:1495501934.0","canEdit":false,"refType":"branch","currentOid":"1405cb1dd7b07f1023bb81e445002bcc5e7ece56"},"tree":{"items":[{"name":"Example/MMWormhole","path":"Example/MMWormhole","contentType":"directory","hasSimplifiedPath":true},{"name":"MMWormhole","path":"MMWormhole","contentType":"directory"},{"name":"Source","path":"Source","contentType":"directory"},{"name":".gitignore","path":".gitignore","contentType":"file"},{"name":"CHANGELOG.md","path":"CHANGELOG.md","contentType":"file"},{"name":"LICENSE","path":"LICENSE","contentType":"file"},{"name":"MMWormhole.gif","path":"MMWormhole.gif","contentType":"file"},{"name":"MMWormhole.podspec","path":"MMWormhole.podspec","contentType":"file"},{"name":"MMWormhole_correct.png","path":"MMWormhole_correct.png","contentType":"file"},{"name":"MMWormhole_incorrect.png","path":"MMWormhole_incorrect.png","contentType":"file"},{"name":"README.md","path":"README.md","contentType":"file"}],"templateDirectorySuggestionUrl":null,"readme":null,"totalCount":11,"showBranchInfobar":false},"fileTree":null,"fileTreeProcessingTime":null,"foldersToFetch":[],"treeExpanded":false,"symbolsExpanded":false,"isOverview":true,"overview":{"banners":{"shouldRecommendReadme":false,"isPersonalRepo":false,"showUseActionBanner":false,"actionSlug":null,"actionId":null,"showProtectBranchBanner":false,"publishBannersInfo":{"dismissActionNoticePath":"/settings/dismiss-notice/publish_action_from_repo","releasePath":"/mutualmobile/MMWormhole/releases/new?marketplace=true","showPublishActionBanner":false},"interactionLimitBanner":null,"showInvitationBanner":false,"inviterName":null,"actionsMigrationBannerInfo":{"releaseTags":[],"showImmutableActionsMigrationBanner":false,"initialMigrationStatus":null}},"codeButton":{"contactPath":"/contact","isEnterprise":false,"local":{"protocolInfo":{"httpAvailable":true,"sshAvailable":null,"httpUrl":"https://github.com/mutualmobile/MMWormhole.git","showCloneWarning":null,"sshUrl":null,"sshCertificatesRequired":null,"sshCertificatesAvailable":null,"ghCliUrl":"gh repo clone mutualmobile/MMWormhole","defaultProtocol":"http","newSshKeyUrl":"/settings/ssh/new","setProtocolPath":"/users/set_protocol"},"platformInfo":{"cloneUrl":"https://desktop.github.com","showVisualStudioCloneButton":false,"visualStudioCloneUrl":"https://windows.github.com","showXcodeCloneButton":false,"xcodeCloneUrl":"xcode://clone?repo=https%3A%2F%2Fgithub.com%2Fmutualmobile%2FMMWormhole","zipballUrl":"/mutualmobile/MMWormhole/archive/refs/heads/master.zip"}},"newCodespacePath":"/codespaces/new?hide_repo_select=true\u0026repo=27653666"},"popovers":{"rename":null,"renamedParentRepo":null},"commitCount":"141","overviewFiles":[{"displayName":"README.md","repoName":"MMWormhole","refName":"master","path":"README.md","preferredFileType":"readme","tabName":"README","richText":"\u003carticle class=\"markdown-body entry-content container-lg\" itemprop=\"text\"\u003e\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eMMWormhole\u003c/h1\u003e\u003ca id=\"user-content-mmwormhole\" class=\"anchor\" aria-label=\"Permalink: MMWormhole\" href=\"#mmwormhole\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eMMWormhole creates a bridge between an iOS or OS X extension and its containing application. The wormhole is meant to be used to pass data or commands back and forth between the two locations. Messages are archived to files which are written to the application's shared App Group. The effect closely resembles interprocess communication between the app and the extension, though true interprocess communication does not exist between extensions and containing apps.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe wormhole also supports CFNotificationCenter Darwin Notifications in an effort to support realtime change notifications. When a message is passed to the wormhole, interested parties can listen and be notified of these changes on either side of the wormhole. The effect is nearly instant updates on either side when a message is sent through the wormhole.\u003c/p\u003e\n\u003cp align=\"center\" dir=\"auto\"\u003e\n\u003ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"/mutualmobile/MMWormhole/blob/master/MMWormhole.gif\"\u003e\u003cimg src=\"/mutualmobile/MMWormhole/raw/master/MMWormhole.gif\" alt=\"Example App\" data-animated-image=\"\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eExample\u003c/h2\u003e\u003ca id=\"user-content-example\" class=\"anchor\" aria-label=\"Permalink: Example\" href=\"#example\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"[self.wormhole passMessageObject:@{@\u0026quot;buttonNumber\u0026quot; : @(1)} identifier:@\u0026quot;button\u0026quot;];\n\n[self.wormhole listenForMessageWithIdentifier:@\u0026quot;button\u0026quot; \n listener:^(id messageObject) {\n self.numberLabel.text = [messageObject[@\u0026quot;buttonNumber\u0026quot;] stringValue];\n}];\"\u003e\u003cpre\u003e[\u003cspan class=\"pl-c1\"\u003eself\u003c/span\u003e.wormhole \u003cspan class=\"pl-c1\"\u003epassMessageObject:\u003c/span\u003e@{\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003ebuttonNumber\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e : @(\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e)} \u003cspan class=\"pl-c1\"\u003eidentifier:\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003ebutton\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e];\n\n[\u003cspan class=\"pl-c1\"\u003eself\u003c/span\u003e.wormhole \u003cspan class=\"pl-c1\"\u003elistenForMessageWithIdentifier:\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003ebutton\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \n \u003cspan class=\"pl-c1\"\u003elistener:\u003c/span\u003e^(\u003cspan class=\"pl-c1\"\u003eid\u003c/span\u003e messageObject) {\n self.\u003cspan class=\"pl-smi\"\u003enumberLabel\u003c/span\u003e.\u003cspan class=\"pl-smi\"\u003etext\u003c/span\u003e = [messageObject[\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003ebuttonNumber\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e] \u003cspan class=\"pl-c1\"\u003estringValue\u003c/span\u003e];\n}];\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eGetting Started\u003c/h2\u003e\u003ca id=\"user-content-getting-started\" class=\"anchor\" aria-label=\"Permalink: Getting Started\" href=\"#getting-started\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eInstall MMWormhole via CocoaPods or by downloading the Source files\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://developer.apple.com/library/ios/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html\" rel=\"nofollow\"\u003eConfigure your App and Extension to support App Groups\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eBegin using MMWormhole to pass messages between your App and Extension\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eNote\u003c/h3\u003e\u003ca id=\"user-content-note\" class=\"anchor\" aria-label=\"Permalink: Note\" href=\"#note\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe MMWormhole Example app will only work with your shared App Group identifiers and Entitlements and is meant purely for reference\u003c/p\u003e\n\u003chr\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eInstalling MMWormhole\u003c/h2\u003e\u003ca id=\"user-content-installing-mmwormhole\" class=\"anchor\" aria-label=\"Permalink: Installing MMWormhole\" href=\"#installing-mmwormhole\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ca target=\"_blank\" rel=\"noopener noreferrer nofollow\" href=\"https://camo.githubusercontent.com/81f283f5e590a4bc9fb85817ce61ac8cb9216d2b789289e72e1ca08f16e71a50/68747470733a2f2f636f636f61706f642d6261646765732e6865726f6b756170702e636f6d2f762f4d4d576f726d686f6c652f62616467652e706e67\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/81f283f5e590a4bc9fb85817ce61ac8cb9216d2b789289e72e1ca08f16e71a50/68747470733a2f2f636f636f61706f642d6261646765732e6865726f6b756170702e636f6d2f762f4d4d576f726d686f6c652f62616467652e706e67\" data-canonical-src=\"https://cocoapod-badges.herokuapp.com/v/MMWormhole/badge.png\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\u003cbr\u003e\nYou can install Wormhole in your project by using \u003ca href=\"https://github.com/cocoapods/cocoapods\"\u003eCocoaPods\u003c/a\u003e:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-ruby notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"pod 'MMWormhole', '~\u0026gt; 2.0.0'\"\u003e\u003cpre\u003e\u003cspan class=\"pl-en\"\u003epod\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e'MMWormhole'\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e'~\u0026gt; 2.0.0'\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"https://github.com/Carthage/Carthage\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/5cb89494518efc818a124fd801726287be9482423d1a161a6dec2066aa0f30db/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f43617274686167652d636f6d70617469626c652d3442433531442e7376673f7374796c653d666c6174\" alt=\"Carthage compatible\" data-canonical-src=\"https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\u003cbr\u003e\nMMWormhole also supports Carthage.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOverview\u003c/h2\u003e\u003ca id=\"user-content-overview\" class=\"anchor\" aria-label=\"Permalink: Overview\" href=\"#overview\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eMMWormhole is designed to make it easy to share very basic information and commands between an extension and it's containing application. The wormhole should remain stable whether the containing app is running or not, but notifications will only be triggered in the containing app if the app is awake in the background. This makes MMWormhole ideal for cases where the containing app is already running via some form of background modes.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eA good way to think of the wormhole is a collection of shared mailboxes. An identifier is essentially a unique mailbox you can send messages to. You know where a message will be delivered to because of the identifier you associate with it, but not necessarily when the message will be picked up by the recipient. If the app or extension are in the background, they may not receive the message immediately. By convention, sending messages should be done from one side to another, not necessarily from yourself to yourself. It's also a good practice to check the contents of your mailbox when your app or extension wakes up, in case any messages have been left there while you were away.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eMMWormhole uses NSKeyedArchiver as a serialization medium, so any object that is NSCoding compliant can work as a message. For many apps, sharing simple strings, numbers, or JSON objects is sufficient to drive the UI of a Widget or Apple Watch app. Messages can be sent and persisted easily as archive files and read later when the app or extension is woken up later.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eUsing MMWormhole is extremely straightforward. The only real catch is that your app and it's extensions must support shared app groups. The group will be used for writing the archive files that represent each message. While larger files and structures, including a whole Core Data database, can be shared using App Groups, MMWormhole is designed to use it's own directory simply to pass messages. Because of that, a best practice is to initialize MMWormhole with a directory name that it will use within your app's shared App Group.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eInitialization\u003c/h3\u003e\u003ca id=\"user-content-initialization\" class=\"anchor\" aria-label=\"Permalink: Initialization\" href=\"#initialization\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eInitialize MMWormhole with your App Group identifier and an optional directory name\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eObjective-C:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"self.wormhole = [[MMWormhole alloc] initWithApplicationGroupIdentifier:@\u0026quot;group.com.mutualmobile.wormhole\u0026quot;\n optionalDirectory:@\u0026quot;wormhole\u0026quot;];\"\u003e\u003cpre\u003eself.wormhole = [[MMWormhole \u003cspan class=\"pl-c1\"\u003ealloc\u003c/span\u003e] \u003cspan class=\"pl-c1\"\u003einitWithApplicationGroupIdentifier:\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003egroup.com.mutualmobile.wormhole\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\n \u003cspan class=\"pl-c1\"\u003eoptionalDirectory:\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003ewormhole\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e];\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSwift:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"let wormhole = MMWormhole(applicationGroupIdentifier: \u0026quot;group.com.mutualmobile.wormhole\u0026quot;, optionalDirectory: \u0026quot;wormhole\u0026quot;)\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ewormhole\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eMMWormhole\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eapplicationGroupIdentifier\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003egroup.com.mutualmobile.wormhole\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e optionalDirectory\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ewormhole\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003ePassing a Message\u003c/h3\u003e\u003ca id=\"user-content-passing-a-message\" class=\"anchor\" aria-label=\"Permalink: Passing a Message\" href=\"#passing-a-message\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003ePass a message with an identifier for the message and a NSCoding compliant object as the message itself\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eObjective-C:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"[self.wormhole passMessageObject:@{@\u0026quot;titleString\u0026quot; : title} \n identifier:@\u0026quot;messageIdentifier\u0026quot;];\"\u003e\u003cpre\u003e[\u003cspan class=\"pl-c1\"\u003eself\u003c/span\u003e.wormhole \u003cspan class=\"pl-c1\"\u003epassMessageObject:\u003c/span\u003e@{\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003etitleString\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e : title} \n \u003cspan class=\"pl-c1\"\u003eidentifier:\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003emessageIdentifier\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e];\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSwift:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"wormhole.passMessageObject(\u0026quot;titleString\u0026quot;, identifier: \u0026quot;messageIdentifier\u0026quot;)\"\u003e\u003cpre\u003ewormhole\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003epassMessageObject\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003etitleString\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e identifier\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003emessageIdentifier\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eReading a Message\u003c/h3\u003e\u003ca id=\"user-content-reading-a-message\" class=\"anchor\" aria-label=\"Permalink: Reading a Message\" href=\"#reading-a-message\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eYou have two options for reading a message. You can obtain the message for an identifier at any time by asking the wormhole for the message.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eObjective-C:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"id messageObject = [self.wormhole messageWithIdentifier:@\u0026quot;messageIdentifier\u0026quot;];\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c1\"\u003eid\u003c/span\u003e messageObject = [\u003cspan class=\"pl-c1\"\u003eself\u003c/span\u003e.wormhole \u003cspan class=\"pl-c1\"\u003emessageWithIdentifier:\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003emessageIdentifier\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e];\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eYou can also listen for changes to that message and be notified when that message is updated.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eObjective-C:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"[self.wormhole listenForMessageWithIdentifier:@\u0026quot;messageIdentifier\u0026quot; \n listener:^(id messageObject) {\n // Do Something\n}];\n\"\u003e\u003cpre\u003e[\u003cspan class=\"pl-c1\"\u003eself\u003c/span\u003e.wormhole \u003cspan class=\"pl-c1\"\u003elistenForMessageWithIdentifier:\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003emessageIdentifier\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e \n \u003cspan class=\"pl-c1\"\u003elistener:\u003c/span\u003e^(\u003cspan class=\"pl-c1\"\u003eid\u003c/span\u003e messageObject) {\n \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e Do Something\u003c/span\u003e\n}];\n\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSwift:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"wormhole.listenForMessageWithIdentifier(\u0026quot;messageIdentifier\u0026quot;, listener: { (messageObject) -\u0026gt; Void in\n if let message: AnyObject = messageObject {\n // Do something\n }\n})\"\u003e\u003cpre\u003ewormhole\u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-en\"\u003elistenForMessageWithIdentifier\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003emessageIdentifier\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e listener\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003emessageObject\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eVoid\u003c/span\u003e \u003cspan class=\"pl-k\"\u003ein\u003c/span\u003e\n \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e \u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e message\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eAnyObject\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e messageObject \u003cspan class=\"pl-kos\"\u003e{\u003c/span\u003e\n // Do something\n \u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\n\u003cspan class=\"pl-kos\"\u003e}\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eDesigning Your Communication Scheme\u003c/h3\u003e\u003ca id=\"user-content-designing-your-communication-scheme\" class=\"anchor\" aria-label=\"Permalink: Designing Your Communication Scheme\" href=\"#designing-your-communication-scheme\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eYou can think of message passing between apps and extensions sort of like a web service. The web service has endpoints that you can read and write. The message identifiers for your MMWormhole messages can be thought of in much the same way. A great practice is to design very clear message identifiers so that you immediately know when reading your code who sent the message and why, and what the possible contents of the message might be. Just like you would design a web service with clear semantics, you should do the same with your wormhole messaging scheme.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCommunication with WatchConnectivity\u003c/h3\u003e\u003ca id=\"user-content-communication-with-watchconnectivity\" class=\"anchor\" aria-label=\"Permalink: Communication with WatchConnectivity\" href=\"#communication-with-watchconnectivity\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe design of your communication scheme is even more important when you need to support watchOS 2. MMWormhole supports the \u003ca href=\"https://developer.apple.com/library/prerelease/watchos/documentation/WatchConnectivity/Reference/WatchConnectivity_framework/index.html#//apple_ref/doc/uid/TP40015269\" rel=\"nofollow\"\u003eWatchConnectivity\u003c/a\u003e framework provided by Apple as an easy way to get up and running quickly with a basic implementation of WatchConnectivity. This support is not intended to replace WatchConnectivity entirely, and it's important to carefully consider your watch app's communication system to see where MMWormhole will fit best.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eHere are two things you need to know if you want to use WatchConnectivity support in your app:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003 8000 e\n\u003cp dir=\"auto\"\u003e\u003ca href=\"http://cocoadocs.org/docsets/MMWormhole/2.0.0/Classes/MMWormholeSession.html\" rel=\"nofollow\"\u003eMMWormholeSession\u003c/a\u003e is a singleton subclass of MMWormhole that supports listening for WatchConnectivity messages. It should be used as the listener for all MMWormhole messages you expect to receive from the WatchConnectivity framework. Be sure to activate the session once your listeners are set so that you can begin receiving message notifications.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp dir=\"auto\"\u003eUse the MMWormholeSessionTransiting types described below when creating your wormholes, but be careful not to send too many messages at once. You can easily overload the pipeline by sending too many messages at once.\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eMessage Transiting Options\u003c/h3\u003e\u003ca id=\"user-content-message-transiting-options\" class=\"anchor\" aria-label=\"Permalink: Message Transiting Options\" href=\"#message-transiting-options\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe mechanism by which data flows through MMWormhole is defined by the \u003ca href=\"http://cocoadocs.org/docsets/MMWormhole/2.0.0/Classes/MMWormholeTransiting.html\" rel=\"nofollow\"\u003eMMWormholeTransiting\u003c/a\u003e protocol. The default implementation of the protocol is called \u003ca href=\"http://cocoadocs.org/docsets/MMWormhole/2.0.0/Classes/MMWormholeFileTransiting.html\" rel=\"nofollow\"\u003eMMWormholeFileTransiting\u003c/a\u003e, which reads and writes messages as archived data files in the app groups shared container. Users of MMWormhole can implement their own version of this protocol to change the message passing behavior.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThere are three new implementations of the MMWormholeTransiting protocol that support the WCSession application context, message, and file transfer systems. You may only use one form of transiting with a wormhole at a time, so you need to consider which type of messaging system best fits a given part of your application.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eMost apps will find the application context system to be a good balance between real time messaging and simple persistence, so we recommend \u003ca href=\"http://cocoadocs.org/docsets/MMWormhole/2.0.0/Classes/MMWormholeSessionContextTransiting.html\" rel=\"nofollow\"\u003eMMWormholeSessionContextTransiting\u003c/a\u003e as the best place to start. Check out the \u003ca href=\"https://developer.apple.com/library/prerelease/watchos/documentation/WatchConnectivity/Reference/WatchConnectivity_framework/index.html#//apple_ref/doc/uid/TP40015269\" rel=\"nofollow\"\u003edocumentation\u003c/a\u003e and header comments for descriptions about the other messaging types.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eYou can get started quickly with a wormhole using one of the built in transiting types by calling the optional initializer to set up an instance with the right transiting type for your use case.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eObjective-C:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-objc notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"self.wormhole = [[MMWormhole alloc] initWithApplicationGroupIdentifier:@\u0026quot;group.com.mutualmobile.wormhole\u0026quot;\n optionalDirectory:@\u0026quot;wormhole\u0026quot;\n \ttransitingType:MMWormholeTransitingTypeSessionContext];\"\u003e\u003cpre\u003eself.wormhole = [[MMWormhole \u003cspan class=\"pl-c1\"\u003ealloc\u003c/span\u003e] \u003cspan class=\"pl-c1\"\u003einitWithApplicationGroupIdentifier:\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003egroup.com.mutualmobile.wormhole\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\n \u003cspan class=\"pl-c1\"\u003eoptionalDirectory:\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e@\"\u003c/span\u003ewormhole\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\n \t\u003cspan class=\"pl-c1\"\u003etransitingType:\u003c/span\u003eMMWormholeTransitingTypeSessionContext];\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eSwift:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-swift notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"let wormhole = MMWormhole(applicationGroupIdentifier: \u0026quot;group.com.mutualmobile.wormhole\u0026quot;, \n\t\t\t\t\t\t\t\t optionalDirectory: \u0026quot;wormhole\u0026quot;,\n\t\t\t\t\t\t\t\t transitingType: .SessionContext)\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003elet\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ewormhole\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eMMWormhole\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e(\u003c/span\u003eapplicationGroupIdentifier\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003egroup.com.mutualmobile.wormhole\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e \n\t\t\t\t\t\t\t\t optionalDirectory\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-s\"\u003ewormhole\u003c/span\u003e\u003cspan class=\"pl-s\"\u003e\"\u003c/span\u003e\u003cspan class=\"pl-kos\"\u003e,\u003c/span\u003e\n\t\t\t\t\t\t\t\t transitingType\u003cspan class=\"pl-kos\"\u003e:\u003c/span\u003e \u003cspan class=\"pl-kos\"\u003e.\u003c/span\u003eSessionContext\u003cspan class=\"pl-kos\"\u003e)\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eRequirements\u003c/h2\u003e\u003ca id=\"user-content-requirements\" class=\"anchor\" aria-label=\"Permalink: Requirements\" href=\"#requirements\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eMMWormhole requires iOS 7.0 or higher or OS X 10.10 or higher.\nMMWormholeSession requires iOS 9.0 or higher.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eTroubleshooting\u003c/h2\u003e\u003ca id=\"user-content-troubleshooting\" class=\"anchor\" aria-label=\"Permalink: Troubleshooting\" href=\"#troubleshooting\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIf messages are not received on the other end, check Project-\u0026gt;Capabilities-\u0026gt;App Groups.\u003cbr\u003e\nThree checkmarks should be displayed in the steps section.\u003c/p\u003e\n\u003cp align=\"center\" dir=\"auto\"\u003e\n\u003ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"/mutualmobile/MMWormhole/blob/master/MMWormhole_correct.png\"\u003e\u003cimg src=\"/mutualmobile/MMWormhole/raw/master/MMWormhole_correct.png\" alt=\"Correct App Group Capabilities\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\" dir=\"auto\"\u003e\n\u003ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"/mutualmobile/MMWormhole/blob/master/MMWormhole_incorrect.png\"\u003e\u003cimg src=\"/mutualmobile/MMWormhole/raw/master/MMWormhole_incorrect.png\" alt=\"Incorrect App Group Capabilities\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eCredits\u003c/h2\u003e\u003ca id=\"user-content-credits\" class=\"anchor\" aria-label=\"Permalink: Credits\" href=\"#credits\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eMMWormhole was created by \u003ca href=\"http://conradstoll.com\" rel=\"nofollow\"\u003eConrad Stoll\u003c/a\u003e at \u003ca href=\"http://www.mutualmobile.com\" rel=\"nofollow\"\u003eMutual Mobile\u003c/a\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eCredit also to \u003ca href=\"https://devforums.apple.com/people/mindsaspire\" rel=\"nofollow\"\u003eWade Spires\u003c/a\u003e, \u003ca href=\"https://twitter.com/atomicbird\" rel=\"nofollow\"\u003eTom Harrington\u003c/a\u003e, and \u003ca href=\"https://twitter.com/rcachatx\" rel=\"nofollow\"\u003eRene Cacheaux\u003c/a\u003e for work and inspiration surrounding notifications between the containing app and it's extensions.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eLicense\u003c/h2\u003e\u003ca id=\"user-content-license\" class=\"anchor\" aria-label=\"Permalink: License\" href=\"#license\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eMMWormhole is available under the MIT license. See the LICENSE file for more info.\u003c/p\u003e\n\u003c/article\u003e","loaded":true,"timedOut":false,"errorMessage":null,"headerInfo":{"toc":[{"level":1,"text":"MMWormhole","anchor":"mmwormhole","htmlText":"MMWormhole"},{"level":2,"text":"Example","anchor":"example","htmlText":"Example"},{"level":2,"text":"Getting Started","anchor":"getting-started","htmlText":"Getting Started"},{"level":3,"text":"Note","anchor":"note","htmlText":"Note"},{"level":2,"text":"Installing MMWormhole","anchor":"installing-mmwormhole","htmlText":"Installing MMWormhole"},{"level":2,"text":"Overview","anchor":"overview","htmlText":"Overview"},{"level":3,"text":"Initialization","anchor":"initialization","htmlText":"Initialization"},{"level":3,"text":"Passing a Message","anchor":"passing-a-message","htmlText":"Passing a Message"},{"level":3,"text":"Reading a Message","anchor":"reading-a-message","htmlText":"Reading a Message"},{"level":3,"text":"Designing Your Communication Scheme","anchor":"designing-your-communication-scheme","htmlText":"Designing Your Communication Scheme"},{"level":3,"text":"Communication with WatchConnectivity","anchor":"communication-with-watchconnectivity","htmlText":"Communication with WatchConnectivity"},{"level":3,"text":"Message Transiting Options","anchor":"message-transiting-options","htmlText":"Message Transiting Options"},{"level":2,"text":"Requirements","anchor":"requirements","htmlText":"Requirements"},{"level":2,"text":"Troubleshooting","anchor":"troubleshooting","htmlText":"Troubleshooting"},{"level":2,"text":"Credits","anchor":"credits","htmlText":"Credits"},{"level":2,"text":"License","anchor":"license","htmlText":"License"}],"siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2Fmutualmobile%2FMMWormhole"}},{"displayName":"LICENSE","repoName":"MMWormhole","refName":"master","path":"LICENSE","preferredFileType":"license","tabName":"MIT","richText":null,"loaded":false,"timedOut":false,"errorMessage":null,"headerInfo":{"toc":null,"siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2Fmutualmobile%2FMMWormhole"}}],"overviewFilesProcessingTime":0}},"appPayload":{"helpUrl":"https://docs.github.com","findFileWorkerPath":"/assets-cdn/worker/find-file-worker-9f8a877aa99f.js","findInFileWorkerPath":"/assets-cdn/worker/find-in-file-worker-96e76d5fdb2c.js","githubDevUrl":null,"enabled_features":{"copilot_workspace":null,"code_nav_ui_events":false,"overview_shared_code_dropdown_button":false,"react_blob_overlay":false,"copilot_conversational_ux_embedding_update":false,"copilot_smell_icebreaker_ux":true,"accessible_code_button":true}}}}

Repository files navigation

MMWormhole

MMWormhole creates a bridge between an iOS or OS X extension and its containing application. The wormhole is meant to be used to pass data or commands back and forth between the two locations. Messages are archived to files which are written to the application's shared App Group. The effect closely resembles interprocess communication between the app and the extension, though true interprocess communication does not exist between extensions and containing apps.

The wormhole also supports CFNotificationCenter Darwin Notifications in an effort to support realtime change notifications. When a message is passed to the wormhole, interested parties can listen and be notified of these changes on either side of the wormhole. The effect is nearly instant updates on either side when a message is sent through the wormhole.

Example App

Example

[self.wormhole passMessageObject:@{@"buttonNumber" : @(1)} identifier:@"button"];

[self.wormhole listenForMessageWithIdentifier:@"button" 
  listener:^(id messageObject) {
    self.numberLabel.text = [messageObject[@"buttonNumber"] stringValue];
}];

Getting Started

Note

The MMWormhole Example app will only work with your shared App Group identifiers and Entitlements and is meant purely for reference


Installing MMWormhole


You can install Wormhole in your project by using CocoaPods:

pod 'MMWormhole', '~> 2.0.0'

Carthage compatible
MMWormhole also supports Carthage.

Overview

MMWormhole is designed to make it easy to share very basic information and commands between an extension and it's containing application. The wormhole should remain stable whether the containing app is running or not, but notifications will only be triggered in the containing app if the app is awake in the background. This makes MMWormhole ideal for cases where the containing app is already running via some form of background modes.

A good way to think of the wormhole is a collection of shared mailboxes. An identifier is essentially a unique mailbox you can send messages to. You know where a message will be delivered to because of the identifier you associate with it, but not necessarily when the message will be picked up by the recipient. If the app or extension are in the background, they may not receive the message immediately. By convention, sending messages should be done from one side to another, not necessarily from yourself to yourself. It's also a good practice to check the contents of your mailbox when your app or extension wakes up, in case any messages have been left there while you were away.

MMWormhole uses NSKeyedArchiver as a serialization medium, so any object that is NSCoding compliant can work as a message. For many apps, sharing simple strings, numbers, or JSON objects is sufficient to drive the UI of a Widget or Apple Watch app. Messages can be sent and persisted easily as archive files and read later when the app or extension is woken up later.

Using MMWormhole is extremely straightforward. The only real catch is that your app and it's extensions must support shared app groups. The group will be used for writing the archive files that represent each message. While larger files and structures, including a whole Core Data database, can be shared using App Groups, MMWormhole is designed to use it's own directory simply to pass messages. Because of that, a best practice is to initialize MMWormhole with a directory name that it will use within your app's shared App Group.

Initialization

Initialize MMWormhole with your App Group identifier and an optional directory name

Objective-C:

self.wormhole = [[MMWormhole alloc] initWithApplicationGroupIdentifier:@"group.com.mutualmobile.wormhole"
                                                     optionalDirectory:@"wormhole"];

Swift:

let wormhole = MMWormhole(applicationGroupIdentifier: "group.com.mutualmobile.wormhole", optionalDirectory: "wormhole")

Passing a Message

Pass a message with an identifier for the message and a NSCoding compliant object as the message itself

Objective-C:

[self.wormhole passMessageObject:@{@"titleString" : titl
8000
e} 
                      identifier:@"messageIdentifier"];

Swift:

wormhole.passMessageObject("titleString", identifier: "messageIdentifier")

Reading a Message

You have two options for reading a message. You can obtain the message for an identifier at any time by asking the wormhole for the message.

Objective-C:

id messageObject = [self.wormhole messageWithIdentifier:@"messageIdentifier"];

You can also listen for changes to that message and be notified when that message is updated.

Objective-C:

[self.wormhole listenForMessageWithIdentifier:@"messageIdentifier" 
 listener:^(id messageObject) {
    // Do Something
}];

Swift:

wormhole.listenForMessageWithIdentifier("messageIdentifier", listener: { (messageObject) -> Void in
    if let message: AnyObject = messageObject {
        // Do something
    }
})

Designing Your Communication Scheme

You can think of message passing between apps and extensions sort of like a web service. The web service has endpoints that you can read and write. The message identifiers for your MMWormhole messages can be thought of in much the same way. A great practice is to design very clear message identifiers so that you immediately know when reading your code who sent the message and why, and what the possible contents of the message might be. Just like you would design a web service with clear semantics, you should do the same with your wormhole messaging scheme.

Communication with WatchConnectivity

The design of your communication scheme is even more important when you need to support watchOS 2. MMWormhole supports the WatchConnectivity framework provided by Apple as an easy way to get up and running quickly with a basic implementation of WatchConnectivity. This support is not intended to replace WatchConnectivity entirely, and it's important to carefully consider your watch app's communication system to see where MMWormhole will fit best.

Here are two things you need to know if you want to use WatchConnectivity support in your app:

  • MMWormholeSession is a singleton subclass of MMWormhole that supports listening for WatchConnectivity messages. It should be used as the listener for all MMWormhole messages you expect to receive from the WatchConnectivity framework. Be sure to activate the session once your listeners are set so that you can begin receiving message notifications.

  • Use the MMWormholeSessionTransiting types described below when creating your wormholes, but be careful not to send too many messages at once. You can easily overload the pipeline by sending too many messages at once.

Message Transiting Options

The mechanism by which data flows through MMWormhole is defined by the MMWormholeTransiting protocol. The default implementation of the protocol is called MMWormholeFileTransiting, which reads and writes messages as archived data files in the app groups shared container. Users of MMWormhole can implement their own version of this protocol to change the message passing behavior.

There are three new implementations of the MMWormholeTransiting protocol that support the WCSession application context, message, and file transfer systems. You may only use one form of transiting with a wormhole at a time, so you need to consider which type of messaging system best fits a given part of your application.

Most apps will find the application context system to be a good balance between real time messaging and simple persistence, so we recommend MMWormholeSessionContextTransiting as the best place to start. Check out the documentation and header comments for descriptions about the other messaging types.

You can get started quickly with a wormhole using one of the built in transiting types by calling the optional initializer to set up an instance with the right transiting type for your use case.

Objective-C:

self.wormhole = [[MMWormhole alloc] initWithApplicationGroupIdentifier:@"group.com.mutualmobile.wormhole"
                                                     optionalDirectory:@"wormhole"
                                                     	transitingType:MMWormholeTransitingTypeSessionContext];

Swift:

let wormhole = MMWormhole(applicationGroupIdentifier: "group.com.mutualmobile.wormhole", 
								   optionalDirectory: "wormhole",
								      transitingType: .SessionContext)

Requirements

MMWormhole requires iOS 7.0 or higher or OS X 10.10 or higher. MMWormholeSession requires iOS 9.0 or higher.

Troubleshooting

If messages are not received on the other end, check Project->Capabilities->App Groups.
Three checkmarks should be displayed in the steps section.

Correct App Group Capabilities

Incorrect App Group Capabilities

Credits

MMWormhole was created by Conrad Stoll at Mutual Mobile.

Credit also to Wade Spires, Tom Harrington, and Rene Cacheaux for work and inspiration surrounding notifications between the containing app and it's extensions.

License

MMWormhole is available under the MIT license. See the LICENSE file for more info.

0