init(serviceType:peerName:defaults:security:invitation:)
@@ -1240,31 +83,41 @@ Parameters
String
This must be the same accross your app running on multiple devices, it must be a short string. Check Apple's docs on MCNearbyServiceAdvertiser
for more info on the limitations for this field.
-
+
- serviceType: This must be the same accross your app running on multiple devices, it must be a short string. Check Apple's docs on
MCNearbyServiceAdvertiser
for more info on the limitations for this field.
+
String
A display name for this peer that will be shown to nearby peers.
+-
+
- peerName: A display name for this peer that will be shown to nearby peers. +
UserDefaults
An instance of UserDefaults
that's used to store this peer's identity so that it remains stable between different sessions. If you use MultipeerKit in app extension make sure to use a shared app group if you wish to maintain a stable identity.
-
+
- defaults: An instance of
UserDefaults
that's used to store this peer's identity so that it remains stable between different sessions. If you use MultipeerKit in app extension make sure to use a shared app group if you wish to maintain a stable identity.
+
Security
The security configuration.
+-
+
- security: The security configuration. +
Invitation
Defines how the multipeer connection handles newly discovered peers. New peers can be invited automatically, invited with a custom context or not invited at all, in which case you must invite them manually.
+-
+
- invitation: Defines how the multipeer connection handles newly discovered peers. New peers can be invited automatically, invited with a custom context or not invited at all, in which case you must invite them manually. +
Parameters
Properties
-
serviceType
@@ -1285,11 +138,11 @@ Check Apple's docs on MCNearbyServiceAdvertiser
for more info on the limitations for this field.
Check Apple's docs on MCNearbyServiceAdvertiser
for more info on the limitations for this field.
peerName
@@ -1299,7 +152,7 @@
defaults
@@ -1311,7 +164,7 @@
security
@@ -1321,7 +174,7 @@
invitation
@@ -1331,7 +184,7 @@
`default`
@@ -1351,7 +204,7 @@
diff --git a/Documentation/MultipeerConfiguration_Invitation/index.html b/Documentation/MultipeerConfiguration_Invitation/index.html
index c333c92..27655a5 100755
--- a/Documentation/MultipeerConfiguration_Invitation/index.html
+++ b/Documentation/MultipeerConfiguration_Invitation/index.html
@@ -4,1178 +4,7 @@
MultipeerKit - MultipeerConfiguration.Invitation
-
+
@@ -1197,7 +26,7 @@
@@ -1215,11 +44,20 @@
or not invited at all, in which case you must invite them manually.
or not invited at all, in which case you must invite them manually.
Relationships
+ +Member Of
+-
+
MultipeerConfiguration
+Configures several aspects of the multipeer communication.
+
+
Enumeration Cases
-
automatic
@@ -1229,7 +67,7 @@
custom
@@ -1240,7 +78,7 @@
none
@@ -1259,7 +97,7 @@
diff --git a/Documentation/MultipeerConfiguration_Security/index.html b/Documentation/MultipeerConfiguration_Security/index.html
index eb3445a..23b4af5 100755
--- a/Documentation/MultipeerConfiguration_Security/index.html
+++ b/Documentation/MultipeerConfiguration_Security/index.html
@@ -4,1178 +4,7 @@
MultipeerKit - MultipeerConfiguration.Security
-
+
@@ -1197,7 +26,7 @@
@@ -1213,11 +42,20 @@
Configures security-related aspects of the multipeer connection.
Configures security-related aspects of the multipeer connection.
Relationships
+ +Member Of
+-
+
MultipeerConfiguration
+Configures several aspects of the multipeer communication.
+
+
Nested Type Aliases
-
InvitationHandler
@@ -1227,7 +65,7 @@
Initializers
-
+
init(identity:encryptionPreference:invitationHandler:)
@@ -1237,7 +75,7 @@
Properties
-
+
identity
@@ -1247,17 +85,17 @@
- The first object in this array should be a SecIdentity
object that provides the local peer’s identity.
-
-The remainder of the array should contain zero or more additional SecCertificate objects that provide any
+
The first object in this array should be a SecIdentity
object that provides the local peer’s identity.
+
+The remainder of the array should contain zero or more additional SecCertificate objects that provide any
intermediate certificates that nearby peers might require when verifying the local peer’s identity.
These certificates should be sent in certificate chain order.
-
-Check Apple's MCSession
docs for more information.
-
+
+Check Apple's MCSession
docs for more information.
+
-
+
encryptionPreference
@@ -1267,7 +105,7 @@
-
+
invitationHandler
@@ -1277,15 +115,15 @@
- It receives the Peer
that sent the invitation, a custom Data
value
+
It receives the Peer
that sent the invitation, a custom Data
value
that's a context that can be used to customize the invitation,
and a closure to be called with true
to accept the invitation or false
to reject it.
-
-The default implementation accepts all invitations.
-
+
+The default implementation accepts all invitations.
+
-
+
`default`
@@ -1304,7 +142,7 @@
diff --git a/Documentation/MultipeerDataSource/index.html b/Documentation/MultipeerDataSource/index.html
index 36c6795..7048ab7 100755
--- a/Documentation/MultipeerDataSource/index.html
+++ b/Documentation/MultipeerDataSource/index.html
@@ -4,1178 +4,7 @@
MultipeerKit - MultipeerDataSource
-
+
@@ -1211,8 +40,8 @@
@available(tvOS 13.0, *) @available(OSX 10.15, *) @available(iOS 13.0, *) public final class MultipeerDataSource: ObservableObject
Relationships
-
-
+
+
-
+
Peer->Identifiable
@@ -1254,7 +83,7 @@ Relationships
Hashable
-
+
Peer->Hashable
@@ -1263,18 +92,34 @@ Relationships
- Inheritance graph for Peer.
-
+ Inheritance graph for Peer.
+
Conforms To
Hashable
Identifiable
+
+ Initializers
+
+
+
+ init(peer:discoveryInfo:)
+
+ init(peer: MCPeerID, discoveryInfo: [String: String]?) throws
+
+
Properties
-
+
+
+ underlyingPeer
+
+ let underlyingPeer: MCPeerID
+
+
id
@@ -1284,7 +129,7 @@
-
+
name
@@ -1294,7 +139,7 @@
-
+
discoveryInfo
@@ -1304,7 +149,7 @@
-
+
isConnected
@@ -1323,7 +168,7 @@
diff --git a/Documentation/all.css b/Documentation/all.css
new file mode 100755
index 0000000..4e9b4a7
--- /dev/null
+++ b/Documentation/all.css
@@ -0,0 +1 @@
+:root{--system-red:#ff3b30;--system-orange:#ff9500;--system-yellow:#fc0;--system-green:#34c759;--system-teal:#5ac8fa;--system-blue:#007aff;--system-indigo:#5856d6;--system-purple:#af52de;--system-pink:#ff2d55;--system-gray:#8e8e93;--system-gray2:#aeaeb2;--system-gray3:#c7c7cc;--system-gray4:#d1d1d6;--system-gray5:#e5e5ea;--system-gray6:#f2f2f7;--label:#000;--secondary-label:#3c3c43;--tertiary-label:#48484a;--quaternary-label:#636366;--placeholder-text:#8e8e93;--link:#007aff;--separator:#e5e5ea;--opaque-separator:#c6c6c8;--system-fill:#787880;--secondary-system-fill:#787880;--tertiary-system-fill:#767680;--quaternary-system-fill:#747480;--system-background:#fff;--secondary-system-background:#f2f2f7;--tertiary-system-background:#fff;--system-grouped-background:#f2f2f7;--secondary-system-grouped-background:#fff;--tertiary-system-grouped-background:#f2f2f7}@supports (color:color(display-p3 1 1 1)){:root{--system-red:color(display-p3 1 0.2314 0.1882);--system-orange:color(display-p3 1 0.5843 0);--system-yellow:color(display-p3 1 0.8 0);--system-green:color(display-p3 0.2039 0.7804 0.349);--system-teal:color(display-p3 0.3529 0.7843 0.9804);--system-blue:color(display-p3 0 0.4784 1);--system-indigo:color(display-p3 0.3451 0.3373 0.8392);--system-purple:color(display-p3 0.6863 0.3216 0.8706);--system-pink:color(display-p3 1 0.1765 0.3333);--system-gray:color(display-p3 0.5569 0.5569 0.5765);--system-gray2:color(display-p3 0.6824 0.6824 0.698);--system-gray3:color(display-p3 0.7804 0.7804 0.8);--system-gray4:color(display-p3 0.8196 0.8196 0.8392);--system-gray5:color(display-p3 0.898 0.898 0.9176);--system-gray6:color(display-p3 0.949 0.949 0.9686);--label:color(display-p3 0 0 0);--secondary-label:color(display-p3 0.2353 0.2353 0.2627);--tertiary-label:color(display-p3 0.2823 0.2823 0.2901);--quaternary-label:color(display-p3 0.4627 0.4627 0.5019);--placeholder-text:color(display-p3 0.5568 0.5568 0.5764);--link:color(display-p3 0 0.4784 1);--separator:color(display-p3 0.898 0.898 0.9176);--opaque-separator:color(display-p3 0.7765 0.7765 0.7843);--system-fill:color(display-p3 0.4706 0.4706 0.502);--secondary-system-fill:color(display-p3 0.4706 0.4706 0.502);--tertiary-system-fill:color(display-p3 0.4627 0.4627 0.502);--quaternary-system-fill:color(display-p3 0.4549 0.4549 0.502);--system-background:color(display-p3 1 1 1);--secondary-system-background:color(display-p3 0.949 0.949 0.9686);--tertiary-system-background:color(display-p3 1 1 1);--system-grouped-background:color(display-p3 0.949 0.949 0.9686);--secondary-system-grouped-background:color(display-p3 1 1 1);--tertiary-system-grouped-background:color(display-p3 0.949 0.949 0.9686)}}:root{--large-title:600 32pt/39pt sans-serif;--title-1:600 26pt/32pt sans-serif;--title-2:600 20pt/25pt sans-serif;--title-3:500 18pt/23pt sans-serif;--headline:500 15pt/20pt sans-serif;--body:300 15pt/20pt sans-serif;--callout:300 14pt/19pt sans-serif;--subhead:300 13pt/18pt sans-serif;--footnote:300 12pt/16pt sans-serif;--caption-1:300 11pt/13pt sans-serif;--caption-2:300 11pt/13pt sans-serif;--icon-case:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%2389c5e6' height='90' rx='8' stroke='%236bb7e1' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M20.21 50c0-20.7 11.9-32.79 30.8-32.79 16 0 28.21 10.33 28.7 25.32H64.19C63.4 35 58.09 30.11 51 30.11c-8.79 0-14.37 7.52-14.37 19.82s5.54 20 14.41 20c7.08 0 12.22-4.66 13.23-12.09h15.52c-.74 15.07-12.43 25-28.78 25C32 82.81 20.21 70.72 20.21 50z' fill='%23fff'/%3E%3C/svg%3E");--icon-class:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%239b98e6' height='90' rx='8' stroke='%235856d6' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='m20.21 50c0-20.7 11.9-32.79 30.8-32.79 16 0 28.21 10.33 28.7 25.32h-15.52c-.79-7.53-6.1-12.42-13.19-12.42-8.79 0-14.37 7.52-14.37 19.82s5.54 20 14.41 20c7.08 0 12.22-4.66 13.23-12.09h15.52c-.74 15.07-12.43 25-28.78 25-19.01-.03-30.8-12.12-30.8-32.84z' fill='%23fff'/%3E%3C/svg%3E");--icon-enumeration:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23eca95b' height='90' rx='8' stroke='%23e89234' stroke-miterlimit='10' stroke-width='4' width='90' x='5.17' y='5'/%3E%3Cpath d='M71.9 81.71H28.43V18.29H71.9v13H44.56v12.62h25.71v11.87H44.56V68.7H71.9z' fill='%23fff'/%3E%3C/svg%3E");--icon-extension:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23eca95b' height='90' rx='8' stroke='%23e89234' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cg fill='%23fff'%3E%3Cpath d='M54.43 81.93H20.51V18.07h33.92v12.26H32.61v13.8h20.45v11.32H32.61v14.22h21.82zM68.74 74.58h-.27l-2.78 7.35h-7.28L64 69.32l-6-12.54h8l2.74 7.3h.27l2.76-7.3h7.64l-6.14 12.54 5.89 12.61h-7.64z'/%3E%3C/g%3E%3C/svg%3E");--icon-function:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M24.25 75.66A5.47 5.47 0 0130 69.93c1.55 0 3.55.41 6.46.41 3.19 0 4.78-1.55 5.46-6.65l1.5-10.14h-9.34a6 6 0 110-12h11.1l1.09-7.27C47.82 23.39 54.28 17.7 64 17.7c6.69 0 11.74 1.77 11.74 6.64A5.47 5.47 0 0170 30.07c-1.55 0-3.55-.41-6.46-.41-3.14 0-4.73 1.51-5.46 6.65l-.78 5.27h11.44a6 6 0 11.05 12H55.6l-1.78 12.11C52.23 76.61 45.72 82.3 36 82.3c-6.7 0-11.75-1.77-11.75-6.64z' fill='%23fff'/%3E%3C/svg%3E");--icon-method:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%235a98f8' height='90' rx='8' stroke='%232974ed' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M70.61 81.71v-39.6h-.31l-15.69 39.6h-9.22l-15.65-39.6h-.35v39.6H15.2V18.29h18.63l16 41.44h.36l16-41.44H84.8v63.42z' fill='%23fff'/%3E%3C/svg%3E");--icon-property:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%2389c5e6' height='90' rx='8' stroke='%236bb7e1' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M52.31 18.29c13.62 0 22.85 8.84 22.85 22.46s-9.71 22.37-23.82 22.37H41v18.59H24.84V18.29zM41 51h7c6.85 0 10.89-3.56 10.89-10.2S54.81 30.64 48 30.64h-7z' fill='%23fff'/%3E%3C/svg%3E");--icon-protocol:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23ff6682' height='90' rx='8' stroke='%23ff2d55' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cg fill='%23fff'%3E%3Cpath d='M46.28 18.29c11.84 0 20 8.66 20 21.71s-8.44 21.71-20.6 21.71H34.87v20H22.78V18.29zM34.87 51.34H43c6.93 0 11-4 11-11.29S50 28.8 43.07 28.8h-8.2zM62 57.45h8v4.77h.16c.84-3.45 2.54-5.12 5.17-5.12a5.06 5.06 0 011.92.35V65a5.69 5.69 0 00-2.39-.51c-3.08 0-4.66 1.74-4.66 5.12v12.1H62z'/%3E%3C/g%3E%3C/svg%3E");--icon-structure:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23b57edf' height='90' rx='8' stroke='%239454c2' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M38.38 63c.74 4.53 5.62 7.16 11.82 7.16s10.37-2.81 10.37-6.68c0-3.51-2.73-5.31-10.24-6.76l-6.5-1.23C31.17 53.14 24.62 47 24.62 37.28c0-12.22 10.59-20.09 25.18-20.09 16 0 25.36 7.83 25.53 19.91h-15c-.26-4.57-4.57-7.29-10.42-7.29s-9.31 2.63-9.31 6.37c0 3.34 2.9 5.18 9.8 6.5l6.5 1.23C70.46 46.51 76.61 52 76.61 62c0 12.74-10 20.83-26.72 20.83-15.82 0-26.28-7.3-26.5-19.78z' fill='%23fff'/%3E%3C/svg%3E");--icon-typealias:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M42 81.71V31.3H24.47v-13h51.06v13H58v50.41z' fill='%23fff'/%3E%3C/svg%3E");--icon-variable:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M39.85 81.71L19.63 18.29H38l12.18 47.64h.35L62.7 18.29h17.67L60.15 81.71z' fill='%23fff'/%3E%3C/svg%3E")}body,button,input,select,textarea{-moz-font-feature-settings:"kern";-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;direction:ltr;font-synthesis:none;text-align:left}h1:first-of-type,h2:first-of-type,h3:first-of-type,h4:first-of-type,h5:first-of-type,h6:first-of-type{margin-top:0}h1 code,h2 code,h3 code,h4 code,h5 code,h6 code{font-family:inherit;font-weight:inherit}h1 img,h2 img,h3 img,h4 img,h5 img,h6 img{margin:0 .5em .2em 0;vertical-align:middle;display:inline-block}h1+*,h2+*,h3+*,h4+*,h5+*,h6+*{margin-top:.8em}img+h1{margin-top:.5em}img+h1,img+h2,img+h3,img+h4,img+h5,img+h6{margin-top:.3em}:is(h1,h2,h3,h4,h5,h6)+:is(h1,h2,h3,h4,h5,h6){margin-top:.4em}:matches(h1,h2,h3,h4,h5,h6)+:matches(h1,h2,h3,h4,h5,h6){margin-top:.4em}:is(p,ul,ol)+:is(h1,h2,h3,h4,h5,h6){margin-top:1.6em}:matches(p,ul,ol)+:matches(h1,h2,h3,h4,h5,h6){margin-top:1.6em}:is(p,ul,ol)+*{margin-top:.8em}:matches(p,ul,ol)+*{margin-top:.8em}ol,ul{margin-left:1.17647em}:matches(ul,ol) :matches(ul,ol){margin-bottom:0;margin-top:0}nav h2{color:#3c3c43;color:var(--secondary-label);font-size:1rem;font-feature-settings:"c2sc";font-variant:small-caps;font-weight:600;text-transform:uppercase}nav ol,nav ul{margin:0;list-style:none}nav li li{font-size:smaller}a:link,a:visited{text-decoration:none}a:hover{text-decoration:underline}a:active{text-decoration:none}a+a{display:inline-block}b,strong{font-weight:600}.discussion,.summary{font:300 14pt/19pt sans-serif;font:var(--callout)}article>.discussion{margin-bottom:2em}.discussion .highlight{background:transparent;border:1px solid #e5e5ea;border:1px solid var(--separator);font:300 11pt/13pt sans-serif;font:var(--caption-1);padding:1em;text-indent:0}cite,dfn,em,i{font-style:italic}:matches(h1,h2,h3) sup{font-size:.4em}sup a{color:inherit;vertical-align:inherit}sup a:hover{color:#007aff;color:var(--link);text-decoration:none}sub{line-height:1}abbr{border:0}:lang(ja),:lang(ko),:lang(th),:lang(zh){font-style:normal}:lang(ko){word-break:keep-all}form fieldset{margin:1em auto;max-width:450px;width:95%}form label{display:block;font-size:1em;font-weight:400;line-height:1.5em;margin-bottom:14px;position:relative;width:100%}input[type=email],input[type=number],input[type=password],input[type=tel],input[type=text],input[type=url],textarea{border-radius:4px;border:1px solid #e5e5ea;border:1px solid var(--separator);color:#333;font-family:inherit;font-size:100%;font-weight:400;height:34px;margin:0;padding:0 1em;position:relative;vertical-align:top;width:100%;z-index:1}input[type=email],input [type=email]:focus,input[type=number],input [type=number]:focus,input[type=password],input [type=password]:focus,input[type=tel],input [type=tel]:focus,input[type=text],input [type=text]:focus,input[type=url],input [type=url]:focus,textarea,textarea:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}input[type=email]:focus,input[type=number]:focus,input[type=password]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=url]:focus,textarea:focus{border-color:#08c;box-shadow:0 0 0 3px rgba(0,136,204,.3);outline:0;z-index:9}input[type=email]:-moz-read-only,input[type=number]:-moz-read-only,input[type=password]:-moz-read-only,input[type=tel]:-moz-read-only,input[type=text]:-moz-read-only,input[type=url]:-moz-read-only,textarea:-moz-read-only{background:none;border:none;box-shadow:none;padding-left:0}input[type=email]:read-only,input[type=number]:read-only,input[type=password]:read-only,input[type=tel]:read-only,input[type=text]:read-only,input[type=url]:read-only,textarea:read-only{background:none;border:none;box-shadow:none;padding-left:0}::-webkit-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::-moz-placeholder{color:#8e8e93;color:var(--placeholder-text)}:-ms-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::-ms-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::placeholder{color:#8e8e93;color:var(--placeholder-text)}textarea{-webkit-overflow-scrolling:touch;line-height:1.4737;min-height:134px;overflow-y:auto;resize:vertical;transform:translateZ(0)}textarea,textarea:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}select{background:transparent;border-radius:4px;border:none;cursor:pointer;font-family:inherit;font-size:1em;height:34px;margin:0;padding:0 1em;width:100%}select,select:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}select:focus{border-color:#08c;box-shadow:0 0 0 3px rgba(0,136,204,.3);outline:0;z-index:9}input[type=file]{background:#fafafa;border-radius:4px;color:#333;cursor:pointer;font-family:inherit;font-size:100%;height:34px;margin:0;padding:6px 1em;position:relative;vertical-align:top;width:100%;z-index:1}input[type=file]:focus{border-color:#08c;outline:0;box-shadow:0 0 0 3px rgba(0,136,204,.3);z-index:9}button,button:focus,input[type=file]:focus,input[type=file]:focus:focus,input[type=reset],input[type=reset]:focus,input[type=submit],input[type=submit]:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}:matches(button,input[type=reset],input[type=submit]){background-color:#e3e3e3;background:linear-gradient(#fff,#e3e3e3);border-color:#d6d6d6;color:#0070c9}:matches(button,input[type=reset],input[type=submit]):hover{background-color:#eee;background:linear-gradient(#fff,#eee);border-color:#d9d9d9}:matches(button,input[type=reset],input[type=submit]):active{background-color:#dcdcdc;background:linear-gradient(#f7f7f7,#dcdcdc);border-color:#d0d0d0}:matches(button,input[type=reset],input[type=submit]):disabled{background-color:#e3e3e3;background:linear-gradient(#fff,#e3e3e3);border-color:#d6d6d6;color:#0070c9}body{background:#f2f2f7;background:var(--system-grouped-background);color:#000;color:var(--label);font-family:ui-system,-apple-system,BlinkMacSystemFont,sans-serif;font:300 15pt/20pt sans-serif;font:var(--body)}h1{font:600 32pt/39pt sans-serif;font:var(--large-title)}h2{font:600 20pt/25pt sans-serif;font:var(--title-2)}h3{font:500 18pt/23pt sans-serif;font:var(--title-3)}h4,h5,h6{font:500 15pt/20pt sans-serif;font:var(--headline)}a{color:#007aff;color:var(--link)}label{font:300 14pt/19pt sans-serif;font:var(--callout)}input,label{display:block}input{margin-bottom:1em}hr{border:none;border-top:1px solid #e5e5ea;border-top:1px solid var(--separator);margin:1em 0}table{width:100%;font:300 11pt/13pt sans-serif;font:var(--caption-1);caption-side:bottom;margin-bottom:2em}td,th{padding:0 1em}th{font-weight:600;text-align:left}thead th{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator)}tr:last-of-type td,tr:last-of-type th{border-bottom:none}td,th{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);color:#3c3c43;color:var(--secondary-label)}caption{color:#48484a;color:var(--tertiary-label);font:300 11pt/13pt sans-serif;font:var(--caption-2);margin-top:2em;text-align:left}.graph text,code{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-weight:300}.graph>polygon{display:none}.graph text{fill:currentColor!important}.graph ellipse,.graph path,.graph polygon,.graph rect{stroke:currentColor!important}body{width:90vw;max-width:1280px;margin:1em auto}body>header{font:600 26pt/32pt sans-serif;font:var(--title-1);padding:.5em 0}body>header a{color:#000;color:var(--label)}body>header span{font-weight:400}body>header sup{text-transform:uppercase;font-size:small;font-weight:300;letter-spacing:.1ch}body>footer,body>header sup{color:#3c3c43;color:var(--secondary-label)}body>footer{clear:both;padding:1em 0;font:300 11pt/13pt sans-serif;font:var(--caption-1)}@media screen and (max-width:768px){body{width:96vw;max-width:100%}body>header{font:500 18pt/23pt sans-serif;font:var(--title-3);text-align:left;padding:1em 0}body>nav{display:none}body>main{padding:0 1em}}@media screen and (max-width:768px){#relationships figure{display:none}section>[role=article][class] pre{margin-left:-2.5em}section>[role=article][class] div{margin-left:-2em}}main,nav{overflow-x:scroll}main{background:#fff;background:var(--system-background);border-radius:8px;padding:0 2em}main section{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);margin-bottom:2em;padding-bottom:1em}main section:last-of-type{border-bottom:none;margin-bottom:0}nav{float:right;margin-left:1em;max-height:100vh;overflow:scroll;padding:0 1em 3em;position:-webkit-sticky;position:sticky;top:1em;width:20vw}nav a{color:#3c3c43;color:var(--secondary-label)}nav ul a{color:#48484a;color:var(--tertiary-label)}nav ol,nav ul{padding:0}nav ul{font:300 14pt/19pt sans-serif;font:var(--callout);margin-bottom:1em}nav ol>li>a{display:block;font-size:smaller;font:500 15pt/20pt sans-serif;font:var(--headline);margin:.5em 0}nav li{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}blockquote{--link:var(--secondary-label);border-left:4px solid #e5e5ea;border-left:4px solid var(--separator);color:#3c3c43;color:var(--secondary-label);font-size:smaller;margin-left:0;padding-left:2em}blockquote a{text-decoration:underline}article{padding:2em 0 1em}article>.summary{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);margin-bottom:2em;padding-bottom:1em}article>.summary:last-child{border-bottom:none}.parameters th{text-align:right}.parameters td{color:#3c3c43;color:var(--secondary-label)}.parameters th+td{text-align:center}dl{padding-top:1em}dt{font:500 15pt/20pt sans-serif;font:var(--headline)}dd{margin-left:2em;margin-bottom:1em}dd p{margin-top:0}.highlight{background:#f2f2f7;background:var(--secondary-system-background);border-radius:8px;font-size:smaller;margin-bottom:2em;overflow-x:scroll;padding:1em 1em 1em 3em;text-indent:-2em;white-space:pre-line}.highlight .p{white-space:nowrap}.highlight .placeholder{color:#000;color:var(--label)}.highlight a{text-decoration:underline;color:#8e8e93;color:var(--placeholder-text)}.highlight .attribute,.highlight .keyword,.highlight .literal{color:#af52de;color:var(--system-purple)}.highlight .number{color:#007aff;color:var(--system-blue)}.highlight .declaration{color:#5ac8fa;color:var(--system-teal)}.highlight .type{color:#5856d6;color:var(--system-indigo)}.highlight .directive{color:#ff9500;color:var(--system-orange)}.highlight .comment{color:#8e8e93;color:var(--system-gray)}main summary:hover{text-decoration:underline}figure{margin:2em 0;padding:1em 0}figure svg{max-width:100%;height:auto!important;margin:0 auto;display:block}h1 small{font-size:.5em;line-height:1.5;display:block;font-weight:400;color:#636366;color:var(--quaternary-label)}dd code,li code,p code{font-size:smaller;color:#3c3c43;color:var(--secondary-label)}a code{text-decoration:underline}dl dt[class],nav li[class],section>[role=article][class]{background-image:var(--background-image);background-size:1em;background-repeat:no-repeat;background-position:left .25em;padding-left:3em}dl dt[class]{background-position-y:.125em}section>[role=article]{margin-bottom:1em;padding-bottom:1em;border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);padding-left:2em!important}section>[role=article]:last-of-type{margin-bottom:0;padding-bottom:0;border-bottom:none}dl dt[class],nav li[class]{list-style:none;text-indent:-1em;margin-bottom:.5em}nav li[class]{padding-left:2.5em}.case,.enumeration_case{--background-image:var(--icon-case);--link:var(--system-teal)}.class{--background-image:var(--icon-class);--link:var(--system-indigo)}.enumeration{--background-image:var(--icon-enumeration)}.enumeration,.extension{--link:var(--system-orange)}.extension{--background-image:var(--icon-extension)}.function{--background-image:var(--icon-function);--link:var(--system-green)}.initializer,.method{--background-image:var(--icon-method);--link:var(--system-blue)}.property{--background-image:var(--icon-property);--link:var(--system-teal)}.protocol{--background-image:var(--icon-protocol);--link:var(--system-pink)}.structure{--background-image:var(--icon-structure);--link:var(--system-purple)}.typealias{--background-image:var(--icon-typealias)}.typealias,.variable{--link:var(--system-green)}.variable{--background-image:var(--icon-variable)}.unknown{--link:var(--quaternary-label);color:#007aff;color:var(--link)}
\ No newline at end of file
diff --git a/Documentation/index.html b/Documentation/index.html
index ece4a00..9b2d3ac 100755
--- a/Documentation/index.html
+++ b/Documentation/index.html
@@ -4,1178 +4,7 @@
MultipeerKit - MultipeerKit
-
+
@@ -1207,7 +36,7 @@ On This Page
Classes
-
-
+
MultipeerDataSource
@@ -1215,7 +44,7 @@ Classes
-
-
+
MultipeerTransceiver
@@ -1229,7 +58,7 @@ Classes
Structures
-
-
+
Peer
@@ -1238,7 +67,7 @@ Structures
-
-
+
MultipeerConfiguration
@@ -1247,7 +76,7 @@ Structures
-
-
+
MultipeerConfiguration.Security
@@ -1261,7 +90,7 @@ Structures
Enumerations
-
-
+
MultipeerConfiguration.Invitation
@@ -1278,7 +107,7 @@ Enumerations
diff --git a/README.md b/README.md
index 55a2b53..1ea415f 100644
--- a/README.md
+++ b/README.md
@@ -22,8 +22,8 @@ let transceiver = MultipeerTransceiver()
transceiver.resume()
// Configure message receivers
-transceiver.receive(SomeCodableThing.self) { payload in
- print("Got my thing! \(payload)")
+transceiver.receive(SomeCodableThing.self) { payload, sender in
+print("Got my thing from \(sender.name)! \(payload)")
}
// Broadcast message to peers
@@ -45,4 +45,4 @@ let package = Package(
],
...
)
-```
\ No newline at end of file
+```
diff --git a/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift b/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift
index f6e257b..7e58550 100644
--- a/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift
+++ b/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift
@@ -1,8 +1,14 @@
import Foundation
+import MultipeerConnectivity.MCPeerID
final class MockMultipeerConnection: MultipeerProtocol {
- var didReceiveData: ((Data, PeerName) -> Void)?
+ let localPeer: Peer = {
+ let underlyingPeer = MCPeerID(displayName: "MockPeer")
+ return try! Peer(peer: underlyingPeer, discoveryInfo: nil)
+ }()
+
+ var didReceiveData: ((Data, Peer) -> Void)?
var didFindPeer: ((Peer) -> Void)?
var didLosePeer: ((Peer) -> Void)?
var didConnectToPeer: ((Peer) -> Void)?
@@ -19,7 +25,7 @@ final class MockMultipeerConnection: MultipeerProtocol {
}
func broadcast(_ data: Data) throws {
- didReceiveData?(data, "MockPeer")
+ didReceiveData?(data, localPeer)
}
func send(_ data: Data, to peers: [Peer]) throws {
@@ -31,7 +37,7 @@ final class MockMultipeerConnection: MultipeerProtocol {
}
func getLocalPeerId() -> String? {
- return "MockId"
+ return localPeer.id
}
}
diff --git a/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift b/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift
index a535eb5..890802f 100644
--- a/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift
+++ b/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift
@@ -27,6 +27,8 @@
import Foundation
struct MultipeerMessage: Codable {
+ static let senderUserInfoKey = CodingUserInfoKey(rawValue: "sender")!
+
let type: String
let payload: Any?
@@ -40,17 +42,17 @@ struct MultipeerMessage: Codable {
case payload
}
- private typealias MessageDecoder = (KeyedDecodingContainer) throws -> Any
+ private typealias MessageDecoder = (KeyedDecodingContainer, Peer) throws -> Any
private typealias MessageEncoder = (Any, inout KeyedEncodingContainer) throws -> Void
private static var decoders: [String: MessageDecoder] = [:]
private static var encoders: [String: MessageEncoder] = [:]
- static func register(_ type: T.Type, for typeName: String, closure: @escaping (T) -> Void) {
- decoders[typeName] = { container in
+ static func register(_ type: T.Type, for typeName: String, closure: @escaping (T, Peer) -> Void) {
+ decoders[typeName] = { container, peer in
let payload = try container.decode(T.self, forKey: .payload)
- DispatchQueue.main.async { closure(payload) }
+ DispatchQueue.main.async { closure(payload, peer) }
return payload
}
@@ -67,9 +69,11 @@ struct MultipeerMessage: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
type = try container.decode(String.self, forKey: .type)
+
+ let sender = decoder.userInfo[MultipeerMessage.senderUserInfoKey]! as! Peer
if let decode = Self.decoders[type] {
- payload = try decode(container)
+ payload = try decode(container, sender)
} else {
payload = nil
}
diff --git a/Sources/MultipeerKit/Internal API/MultipeerConnection.swift b/Sources/MultipeerKit/Internal API/MultipeerConnection.swift
index 0ed0bfe..e8420a0 100644
--- a/Sources/MultipeerKit/Internal API/MultipeerConnection.swift
+++ b/Sources/MultipeerKit/Internal API/MultipeerConnection.swift
@@ -27,7 +27,7 @@ final class MultipeerConnection: NSObject, MultipeerProtocol {
self.me = MCPeerID.fetchOrCreate(with: configuration)
}
- var didReceiveData: ((Data, PeerName) -> Void)?
+ var didReceiveData: ((Data, Peer) -> Void)?
var didFindPeer: ((Peer) -> Void)?
var didLosePeer: ((Peer) -> Void)?
var didConnectToPeer: ((Peer) -> Void)?
@@ -145,7 +145,11 @@ extension MultipeerConnection: MCSessionDelegate {
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
os_log("%{public}@", log: log, type: .debug, #function)
- didReceiveData?(data, peerID.displayName)
+ if let peer = try? Peer(peer: peerID, discoveryInfo: nil) {
+ didReceiveData?(data, peer)
+ } else {
+ os_log("Received data, but cannot create peer for %s", log: log, type: .error, #function, peerID.displayName)
+ }
}
func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {
diff --git a/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift b/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift
index cab54b9..97f63b5 100644
--- a/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift
+++ b/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift
@@ -4,7 +4,7 @@ typealias PeerName = String
protocol MultipeerProtocol: AnyObject {
- var didReceiveData: ((Data, PeerName) -> Void)? { get set }
+ var didReceiveData: ((Data, Peer) -> Void)? { get set }
var didFindPeer: ((Peer) -> Void)? { get set }
var didLosePeer: ((Peer) -> Void)? { get set }
var didConnectToPeer: ((Peer) -> Void)? { get set }
diff --git a/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift b/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift
index 2b0828d..0ab3447 100644
--- a/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift
+++ b/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift
@@ -74,12 +74,13 @@ public final class MultipeerTransceiver {
/// - type: The `Codable` type to receive.
/// - closure: The closure that will be called whenever a payload of the specified type is received.
/// - payload: The payload decoded from the remote message.
+ /// - sender: The remote peer who sent the message.
///
/// MultipeerKit communicates data between peers as JSON-encoded payloads which originate with
/// `Codable` entities. You register a closure to handle each specific type of entity,
/// and this closure is automatically called by the framework when a remote peer sends
/// a message containing an entity that decodes to the specified type.
- public func receive(_ type: T.Type, using closure: @escaping (_ payload: T) -> Void) {
+ public func receive(_ type: T.Type, using closure: @escaping (_ payload: T, _ sender: Peer) -> Void) {
MultipeerMessage.register(type, for: String(describing: type), closure: closure)
}
@@ -127,11 +128,13 @@ public final class MultipeerTransceiver {
}
}
- private func handleDataReceived(_ data: Data, from peer: PeerName) {
+ private func handleDataReceived(_ data: Data, from peer: Peer) {
os_log("%{public}@", log: log, type: .debug, #function)
do {
- let message = try JSONDecoder().decode(MultipeerMessage.self, from: data)
+ let decoder = JSONDecoder()
+ decoder.userInfo[MultipeerMessage.senderUserInfoKey] = peer
+ let message = try decoder.decode(MultipeerMessage.self, from: data)
os_log("Received message %@", log: self.log, type: .debug, String(describing: message))
} catch {
diff --git a/Tests/MultipeerKitTests/MultipeerKitTests.swift b/Tests/MultipeerKitTests/MultipeerKitTests.swift
index 6e993a8..4cdbc8d 100644
--- a/Tests/MultipeerKitTests/MultipeerKitTests.swift
+++ b/Tests/MultipeerKitTests/MultipeerKitTests.swift
@@ -36,8 +36,9 @@ final class MultipeerKitTests: XCTestCase {
let expect = XCTestExpectation(description: "Receive payload")
- mock.receive(TestPayload.self) { p in
- XCTAssertEqual(p, tsPayload)
+ mock.receive(TestPayload.self) { payload, sender in
+ XCTAssertEqual(payload, tsPayload)
+ XCTAssertEqual(sender.id, mock.localPeerId!)
expect.fulfill()
}
diff --git a/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift b/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift
index 9f0143c..9de1890 100644
--- a/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift
+++ b/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift
@@ -24,10 +24,10 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
let t = MultipeerTransceiver(configuration: config)
- t.receive(ExamplePayload.self) { [weak self] payload in
+ t.receive(ExamplePayload.self) { [weak self] payload, peer in
print("Got payload: \(payload)")
- self?.notify(with: payload)
+ self?.notify(with: payload, peer: peer)
}
return t
@@ -37,9 +37,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
MultipeerDataSource(transceiver: transceiver)
}()
- private func notify(with payload: ExamplePayload) {
+ private func notify(with payload: ExamplePayload, peer: Peer) {
let content = UNMutableNotificationContent()
- content.body = payload.message
+ content.body = "\"\(payload.message)\" from \(peer.name)"
let request = UNNotificationRequest(identifier: payload.message, content: content, trigger: nil)
UNUserNotificationCenter.current().add(request) { _ in
Initializers
-
init(identity:encryptionPreference:invitationHandler:)
@@ -1237,7 +75,7 @@
Properties
-
+
identity
@@ -1247,17 +85,17 @@
- The first object in this array should be a SecIdentity
object that provides the local peer’s identity.
-
-The remainder of the array should contain zero or more additional SecCertificate objects that provide any
+
The first object in this array should be a SecIdentity
object that provides the local peer’s identity.
+
+The remainder of the array should contain zero or more additional SecCertificate objects that provide any
intermediate certificates that nearby peers might require when verifying the local peer’s identity.
These certificates should be sent in certificate chain order.
-
-Check Apple's MCSession
docs for more information.
-
+
+Check Apple's MCSession
docs for more information.
+
-
+
encryptionPreference
@@ -1267,7 +105,7 @@
-
+
invitationHandler
@@ -1277,15 +115,15 @@
- It receives the Peer
that sent the invitation, a custom Data
value
+
It receives the Peer
that sent the invitation, a custom Data
value
that's a context that can be used to customize the invitation,
and a closure to be called with true
to accept the invitation or false
to reject it.
-
-The default implementation accepts all invitations.
-
+
+The default implementation accepts all invitations.
+
-
+
`default`
@@ -1304,7 +142,7 @@
diff --git a/Documentation/MultipeerDataSource/index.html b/Documentation/MultipeerDataSource/index.html
index 36c6795..7048ab7 100755
--- a/Documentation/MultipeerDataSource/index.html
+++ b/Documentation/MultipeerDataSource/index.html
@@ -4,1178 +4,7 @@
MultipeerKit - MultipeerDataSource
-
+
@@ -1211,8 +40,8 @@
@available(tvOS 13.0, *) @available(OSX 10.15, *) @available(iOS 13.0, *) public final class MultipeerDataSource: ObservableObject
Relationships
-
-
+
+
-
+
Peer->Identifiable
@@ -1254,7 +83,7 @@ Relationships
Hashable
-
+
Peer->Hashable
@@ -1263,18 +92,34 @@ Relationships
- Inheritance graph for Peer.
-
+ Inheritance graph for Peer.
+
Conforms To
Hashable
Identifiable
+
+ Initializers
+
+
+
+ init(peer:discoveryInfo:)
+
+ init(peer: MCPeerID, discoveryInfo: [String: String]?) throws
+
+
Properties
-
+
+
+ underlyingPeer
+
+ let underlyingPeer: MCPeerID
+
+
id
@@ -1284,7 +129,7 @@
-
+
name
@@ -1294,7 +139,7 @@
-
+
discoveryInfo
@@ -1304,7 +149,7 @@
-
+
isConnected
@@ -1323,7 +168,7 @@
diff --git a/Documentation/all.css b/Documentation/all.css
new file mode 100755
index 0000000..4e9b4a7
--- /dev/null
+++ b/Documentation/all.css
@@ -0,0 +1 @@
+:root{--system-red:#ff3b30;--system-orange:#ff9500;--system-yellow:#fc0;--system-green:#34c759;--system-teal:#5ac8fa;--system-blue:#007aff;--system-indigo:#5856d6;--system-purple:#af52de;--system-pink:#ff2d55;--system-gray:#8e8e93;--system-gray2:#aeaeb2;--system-gray3:#c7c7cc;--system-gray4:#d1d1d6;--system-gray5:#e5e5ea;--system-gray6:#f2f2f7;--label:#000;--secondary-label:#3c3c43;--tertiary-label:#48484a;--quaternary-label:#636366;--placeholder-text:#8e8e93;--link:#007aff;--separator:#e5e5ea;--opaque-separator:#c6c6c8;--system-fill:#787880;--secondary-system-fill:#787880;--tertiary-system-fill:#767680;--quaternary-system-fill:#747480;--system-background:#fff;--secondary-system-background:#f2f2f7;--tertiary-system-background:#fff;--system-grouped-background:#f2f2f7;--secondary-system-grouped-background:#fff;--tertiary-system-grouped-background:#f2f2f7}@supports (color:color(display-p3 1 1 1)){:root{--system-red:color(display-p3 1 0.2314 0.1882);--system-orange:color(display-p3 1 0.5843 0);--system-yellow:color(display-p3 1 0.8 0);--system-green:color(display-p3 0.2039 0.7804 0.349);--system-teal:color(display-p3 0.3529 0.7843 0.9804);--system-blue:color(display-p3 0 0.4784 1);--system-indigo:color(display-p3 0.3451 0.3373 0.8392);--system-purple:color(display-p3 0.6863 0.3216 0.8706);--system-pink:color(display-p3 1 0.1765 0.3333);--system-gray:color(display-p3 0.5569 0.5569 0.5765);--system-gray2:color(display-p3 0.6824 0.6824 0.698);--system-gray3:color(display-p3 0.7804 0.7804 0.8);--system-gray4:color(display-p3 0.8196 0.8196 0.8392);--system-gray5:color(display-p3 0.898 0.898 0.9176);--system-gray6:color(display-p3 0.949 0.949 0.9686);--label:color(display-p3 0 0 0);--secondary-label:color(display-p3 0.2353 0.2353 0.2627);--tertiary-label:color(display-p3 0.2823 0.2823 0.2901);--quaternary-label:color(display-p3 0.4627 0.4627 0.5019);--placeholder-text:color(display-p3 0.5568 0.5568 0.5764);--link:color(display-p3 0 0.4784 1);--separator:color(display-p3 0.898 0.898 0.9176);--opaque-separator:color(display-p3 0.7765 0.7765 0.7843);--system-fill:color(display-p3 0.4706 0.4706 0.502);--secondary-system-fill:color(display-p3 0.4706 0.4706 0.502);--tertiary-system-fill:color(display-p3 0.4627 0.4627 0.502);--quaternary-system-fill:color(display-p3 0.4549 0.4549 0.502);--system-background:color(display-p3 1 1 1);--secondary-system-background:color(display-p3 0.949 0.949 0.9686);--tertiary-system-background:color(display-p3 1 1 1);--system-grouped-background:color(display-p3 0.949 0.949 0.9686);--secondary-system-grouped-background:color(display-p3 1 1 1);--tertiary-system-grouped-background:color(display-p3 0.949 0.949 0.9686)}}:root{--large-title:600 32pt/39pt sans-serif;--title-1:600 26pt/32pt sans-serif;--title-2:600 20pt/25pt sans-serif;--title-3:500 18pt/23pt sans-serif;--headline:500 15pt/20pt sans-serif;--body:300 15pt/20pt sans-serif;--callout:300 14pt/19pt sans-serif;--subhead:300 13pt/18pt sans-serif;--footnote:300 12pt/16pt sans-serif;--caption-1:300 11pt/13pt sans-serif;--caption-2:300 11pt/13pt sans-serif;--icon-case:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%2389c5e6' height='90' rx='8' stroke='%236bb7e1' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M20.21 50c0-20.7 11.9-32.79 30.8-32.79 16 0 28.21 10.33 28.7 25.32H64.19C63.4 35 58.09 30.11 51 30.11c-8.79 0-14.37 7.52-14.37 19.82s5.54 20 14.41 20c7.08 0 12.22-4.66 13.23-12.09h15.52c-.74 15.07-12.43 25-28.78 25C32 82.81 20.21 70.72 20.21 50z' fill='%23fff'/%3E%3C/svg%3E");--icon-class:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%239b98e6' height='90' rx='8' stroke='%235856d6' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='m20.21 50c0-20.7 11.9-32.79 30.8-32.79 16 0 28.21 10.33 28.7 25.32h-15.52c-.79-7.53-6.1-12.42-13.19-12.42-8.79 0-14.37 7.52-14.37 19.82s5.54 20 14.41 20c7.08 0 12.22-4.66 13.23-12.09h15.52c-.74 15.07-12.43 25-28.78 25-19.01-.03-30.8-12.12-30.8-32.84z' fill='%23fff'/%3E%3C/svg%3E");--icon-enumeration:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23eca95b' height='90' rx='8' stroke='%23e89234' stroke-miterlimit='10' stroke-width='4' width='90' x='5.17' y='5'/%3E%3Cpath d='M71.9 81.71H28.43V18.29H71.9v13H44.56v12.62h25.71v11.87H44.56V68.7H71.9z' fill='%23fff'/%3E%3C/svg%3E");--icon-extension:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23eca95b' height='90' rx='8' stroke='%23e89234' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cg fill='%23fff'%3E%3Cpath d='M54.43 81.93H20.51V18.07h33.92v12.26H32.61v13.8h20.45v11.32H32.61v14.22h21.82zM68.74 74.58h-.27l-2.78 7.35h-7.28L64 69.32l-6-12.54h8l2.74 7.3h.27l2.76-7.3h7.64l-6.14 12.54 5.89 12.61h-7.64z'/%3E%3C/g%3E%3C/svg%3E");--icon-function:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M24.25 75.66A5.47 5.47 0 0130 69.93c1.55 0 3.55.41 6.46.41 3.19 0 4.78-1.55 5.46-6.65l1.5-10.14h-9.34a6 6 0 110-12h11.1l1.09-7.27C47.82 23.39 54.28 17.7 64 17.7c6.69 0 11.74 1.77 11.74 6.64A5.47 5.47 0 0170 30.07c-1.55 0-3.55-.41-6.46-.41-3.14 0-4.73 1.51-5.46 6.65l-.78 5.27h11.44a6 6 0 11.05 12H55.6l-1.78 12.11C52.23 76.61 45.72 82.3 36 82.3c-6.7 0-11.75-1.77-11.75-6.64z' fill='%23fff'/%3E%3C/svg%3E");--icon-method:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%235a98f8' height='90' rx='8' stroke='%232974ed' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M70.61 81.71v-39.6h-.31l-15.69 39.6h-9.22l-15.65-39.6h-.35v39.6H15.2V18.29h18.63l16 41.44h.36l16-41.44H84.8v63.42z' fill='%23fff'/%3E%3C/svg%3E");--icon-property:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%2389c5e6' height='90' rx='8' stroke='%236bb7e1' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M52.31 18.29c13.62 0 22.85 8.84 22.85 22.46s-9.71 22.37-23.82 22.37H41v18.59H24.84V18.29zM41 51h7c6.85 0 10.89-3.56 10.89-10.2S54.81 30.64 48 30.64h-7z' fill='%23fff'/%3E%3C/svg%3E");--icon-protocol:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23ff6682' height='90' rx='8' stroke='%23ff2d55' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cg fill='%23fff'%3E%3Cpath d='M46.28 18.29c11.84 0 20 8.66 20 21.71s-8.44 21.71-20.6 21.71H34.87v20H22.78V18.29zM34.87 51.34H43c6.93 0 11-4 11-11.29S50 28.8 43.07 28.8h-8.2zM62 57.45h8v4.77h.16c.84-3.45 2.54-5.12 5.17-5.12a5.06 5.06 0 011.92.35V65a5.69 5.69 0 00-2.39-.51c-3.08 0-4.66 1.74-4.66 5.12v12.1H62z'/%3E%3C/g%3E%3C/svg%3E");--icon-structure:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23b57edf' height='90' rx='8' stroke='%239454c2' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M38.38 63c.74 4.53 5.62 7.16 11.82 7.16s10.37-2.81 10.37-6.68c0-3.51-2.73-5.31-10.24-6.76l-6.5-1.23C31.17 53.14 24.62 47 24.62 37.28c0-12.22 10.59-20.09 25.18-20.09 16 0 25.36 7.83 25.53 19.91h-15c-.26-4.57-4.57-7.29-10.42-7.29s-9.31 2.63-9.31 6.37c0 3.34 2.9 5.18 9.8 6.5l6.5 1.23C70.46 46.51 76.61 52 76.61 62c0 12.74-10 20.83-26.72 20.83-15.82 0-26.28-7.3-26.5-19.78z' fill='%23fff'/%3E%3C/svg%3E");--icon-typealias:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M42 81.71V31.3H24.47v-13h51.06v13H58v50.41z' fill='%23fff'/%3E%3C/svg%3E");--icon-variable:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M39.85 81.71L19.63 18.29H38l12.18 47.64h.35L62.7 18.29h17.67L60.15 81.71z' fill='%23fff'/%3E%3C/svg%3E")}body,button,input,select,textarea{-moz-font-feature-settings:"kern";-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;direction:ltr;font-synthesis:none;text-align:left}h1:first-of-type,h2:first-of-type,h3:first-of-type,h4:first-of-type,h5:first-of-type,h6:first-of-type{margin-top:0}h1 code,h2 code,h3 code,h4 code,h5 code,h6 code{font-family:inherit;font-weight:inherit}h1 img,h2 img,h3 img,h4 img,h5 img,h6 img{margin:0 .5em .2em 0;vertical-align:middle;display:inline-block}h1+*,h2+*,h3+*,h4+*,h5+*,h6+*{margin-top:.8em}img+h1{margin-top:.5em}img+h1,img+h2,img+h3,img+h4,img+h5,img+h6{margin-top:.3em}:is(h1,h2,h3,h4,h5,h6)+:is(h1,h2,h3,h4,h5,h6){margin-top:.4em}:matches(h1,h2,h3,h4,h5,h6)+:matches(h1,h2,h3,h4,h5,h6){margin-top:.4em}:is(p,ul,ol)+:is(h1,h2,h3,h4,h5,h6){margin-top:1.6em}:matches(p,ul,ol)+:matches(h1,h2,h3,h4,h5,h6){margin-top:1.6em}:is(p,ul,ol)+*{margin-top:.8em}:matches(p,ul,ol)+*{margin-top:.8em}ol,ul{margin-left:1.17647em}:matches(ul,ol) :matches(ul,ol){margin-bottom:0;margin-top:0}nav h2{color:#3c3c43;color:var(--secondary-label);font-size:1rem;font-feature-settings:"c2sc";font-variant:small-caps;font-weight:600;text-transform:uppercase}nav ol,nav ul{margin:0;list-style:none}nav li li{font-size:smaller}a:link,a:visited{text-decoration:none}a:hover{text-decoration:underline}a:active{text-decoration:none}a+a{display:inline-block}b,strong{font-weight:600}.discussion,.summary{font:300 14pt/19pt sans-serif;font:var(--callout)}article>.discussion{margin-bottom:2em}.discussion .highlight{background:transparent;border:1px solid #e5e5ea;border:1px solid var(--separator);font:300 11pt/13pt sans-serif;font:var(--caption-1);padding:1em;text-indent:0}cite,dfn,em,i{font-style:italic}:matches(h1,h2,h3) sup{font-size:.4em}sup a{color:inherit;vertical-align:inherit}sup a:hover{color:#007aff;color:var(--link);text-decoration:none}sub{line-height:1}abbr{border:0}:lang(ja),:lang(ko),:lang(th),:lang(zh){font-style:normal}:lang(ko){word-break:keep-all}form fieldset{margin:1em auto;max-width:450px;width:95%}form label{display:block;font-size:1em;font-weight:400;line-height:1.5em;margin-bottom:14px;position:relative;width:100%}input[type=email],input[type=number],input[type=password],input[type=tel],input[type=text],input[type=url],textarea{border-radius:4px;border:1px solid #e5e5ea;border:1px solid var(--separator);color:#333;font-family:inherit;font-size:100%;font-weight:400;height:34px;margin:0;padding:0 1em;position:relative;vertical-align:top;width:100%;z-index:1}input[type=email],input [type=email]:focus,input[type=number],input [type=number]:focus,input[type=password],input [type=password]:focus,input[type=tel],input [type=tel]:focus,input[type=text],input [type=text]:focus,input[type=url],input [type=url]:focus,textarea,textarea:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}input[type=email]:focus,input[type=number]:focus,input[type=password]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=url]:focus,textarea:focus{border-color:#08c;box-shadow:0 0 0 3px rgba(0,136,204,.3);outline:0;z-index:9}input[type=email]:-moz-read-only,input[type=number]:-moz-read-only,input[type=password]:-moz-read-only,input[type=tel]:-moz-read-only,input[type=text]:-moz-read-only,input[type=url]:-moz-read-only,textarea:-moz-read-only{background:none;border:none;box-shadow:none;padding-left:0}input[type=email]:read-only,input[type=number]:read-only,input[type=password]:read-only,input[type=tel]:read-only,input[type=text]:read-only,input[type=url]:read-only,textarea:read-only{background:none;border:none;box-shadow:none;padding-left:0}::-webkit-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::-moz-placeholder{color:#8e8e93;color:var(--placeholder-text)}:-ms-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::-ms-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::placeholder{color:#8e8e93;color:var(--placeholder-text)}textarea{-webkit-overflow-scrolling:touch;line-height:1.4737;min-height:134px;overflow-y:auto;resize:vertical;transform:translateZ(0)}textarea,textarea:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}select{background:transparent;border-radius:4px;border:none;cursor:pointer;font-family:inherit;font-size:1em;height:34px;margin:0;padding:0 1em;width:100%}select,select:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}select:focus{border-color:#08c;box-shadow:0 0 0 3px rgba(0,136,204,.3);outline:0;z-index:9}input[type=file]{background:#fafafa;border-radius:4px;color:#333;cursor:pointer;font-family:inherit;font-size:100%;height:34px;margin:0;padding:6px 1em;position:relative;vertical-align:top;width:100%;z-index:1}input[type=file]:focus{border-color:#08c;outline:0;box-shadow:0 0 0 3px rgba(0,136,204,.3);z-index:9}button,button:focus,input[type=file]:focus,input[type=file]:focus:focus,input[type=reset],input[type=reset]:focus,input[type=submit],input[type=submit]:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}:matches(button,input[type=reset],input[type=submit]){background-color:#e3e3e3;background:linear-gradient(#fff,#e3e3e3);border-color:#d6d6d6;color:#0070c9}:matches(button,input[type=reset],input[type=submit]):hover{background-color:#eee;background:linear-gradient(#fff,#eee);border-color:#d9d9d9}:matches(button,input[type=reset],input[type=submit]):active{background-color:#dcdcdc;background:linear-gradient(#f7f7f7,#dcdcdc);border-color:#d0d0d0}:matches(button,input[type=reset],input[type=submit]):disabled{background-color:#e3e3e3;background:linear-gradient(#fff,#e3e3e3);border-color:#d6d6d6;color:#0070c9}body{background:#f2f2f7;background:var(--system-grouped-background);color:#000;color:var(--label);font-family:ui-system,-apple-system,BlinkMacSystemFont,sans-serif;font:300 15pt/20pt sans-serif;font:var(--body)}h1{font:600 32pt/39pt sans-serif;font:var(--large-title)}h2{font:600 20pt/25pt sans-serif;font:var(--title-2)}h3{font:500 18pt/23pt sans-serif;font:var(--title-3)}h4,h5,h6{font:500 15pt/20pt sans-serif;font:var(--headline)}a{color:#007aff;color:var(--link)}label{font:300 14pt/19pt sans-serif;font:var(--callout)}input,label{display:block}input{margin-bottom:1em}hr{border:none;border-top:1px solid #e5e5ea;border-top:1px solid var(--separator);margin:1em 0}table{width:100%;font:300 11pt/13pt sans-serif;font:var(--caption-1);caption-side:bottom;margin-bottom:2em}td,th{padding:0 1em}th{font-weight:600;text-align:left}thead th{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator)}tr:last-of-type td,tr:last-of-type th{border-bottom:none}td,th{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);color:#3c3c43;color:var(--secondary-label)}caption{color:#48484a;color:var(--tertiary-label);font:300 11pt/13pt sans-serif;font:var(--caption-2);margin-top:2em;text-align:left}.graph text,code{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-weight:300}.graph>polygon{display:none}.graph text{fill:currentColor!important}.graph ellipse,.graph path,.graph polygon,.graph rect{stroke:currentColor!important}body{width:90vw;max-width:1280px;margin:1em auto}body>header{font:600 26pt/32pt sans-serif;font:var(--title-1);padding:.5em 0}body>header a{color:#000;color:var(--label)}body>header span{font-weight:400}body>header sup{text-transform:uppercase;font-size:small;font-weight:300;letter-spacing:.1ch}body>footer,body>header sup{color:#3c3c43;color:var(--secondary-label)}body>footer{clear:both;padding:1em 0;font:300 11pt/13pt sans-serif;font:var(--caption-1)}@media screen and (max-width:768px){body{width:96vw;max-width:100%}body>header{font:500 18pt/23pt sans-serif;font:var(--title-3);text-align:left;padding:1em 0}body>nav{display:none}body>main{padding:0 1em}}@media screen and (max-width:768px){#relationships figure{display:none}section>[role=article][class] pre{margin-left:-2.5em}section>[role=article][class] div{margin-left:-2em}}main,nav{overflow-x:scroll}main{background:#fff;background:var(--system-background);border-radius:8px;padding:0 2em}main section{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);margin-bottom:2em;padding-bottom:1em}main section:last-of-type{border-bottom:none;margin-bottom:0}nav{float:right;margin-left:1em;max-height:100vh;overflow:scroll;padding:0 1em 3em;position:-webkit-sticky;position:sticky;top:1em;width:20vw}nav a{color:#3c3c43;color:var(--secondary-label)}nav ul a{color:#48484a;color:var(--tertiary-label)}nav ol,nav ul{padding:0}nav ul{font:300 14pt/19pt sans-serif;font:var(--callout);margin-bottom:1em}nav ol>li>a{display:block;font-size:smaller;font:500 15pt/20pt sans-serif;font:var(--headline);margin:.5em 0}nav li{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}blockquote{--link:var(--secondary-label);border-left:4px solid #e5e5ea;border-left:4px solid var(--separator);color:#3c3c43;color:var(--secondary-label);font-size:smaller;margin-left:0;padding-left:2em}blockquote a{text-decoration:underline}article{padding:2em 0 1em}article>.summary{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);margin-bottom:2em;padding-bottom:1em}article>.summary:last-child{border-bottom:none}.parameters th{text-align:right}.parameters td{color:#3c3c43;color:var(--secondary-label)}.parameters th+td{text-align:center}dl{padding-top:1em}dt{font:500 15pt/20pt sans-serif;font:var(--headline)}dd{margin-left:2em;margin-bottom:1em}dd p{margin-top:0}.highlight{background:#f2f2f7;background:var(--secondary-system-background);border-radius:8px;font-size:smaller;margin-bottom:2em;overflow-x:scroll;padding:1em 1em 1em 3em;text-indent:-2em;white-space:pre-line}.highlight .p{white-space:nowrap}.highlight .placeholder{color:#000;color:var(--label)}.highlight a{text-decoration:underline;color:#8e8e93;color:var(--placeholder-text)}.highlight .attribute,.highlight .keyword,.highlight .literal{color:#af52de;color:var(--system-purple)}.highlight .number{color:#007aff;color:var(--system-blue)}.highlight .declaration{color:#5ac8fa;color:var(--system-teal)}.highlight .type{color:#5856d6;color:var(--system-indigo)}.highlight .directive{color:#ff9500;color:var(--system-orange)}.highlight .comment{color:#8e8e93;color:var(--system-gray)}main summary:hover{text-decoration:underline}figure{margin:2em 0;padding:1em 0}figure svg{max-width:100%;height:auto!important;margin:0 auto;display:block}h1 small{font-size:.5em;line-height:1.5;display:block;font-weight:400;color:#636366;color:var(--quaternary-label)}dd code,li code,p code{font-size:smaller;color:#3c3c43;color:var(--secondary-label)}a code{text-decoration:underline}dl dt[class],nav li[class],section>[role=article][class]{background-image:var(--background-image);background-size:1em;background-repeat:no-repeat;background-position:left .25em;padding-left:3em}dl dt[class]{background-position-y:.125em}section>[role=article]{margin-bottom:1em;padding-bottom:1em;border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);padding-left:2em!important}section>[role=article]:last-of-type{margin-bottom:0;padding-bottom:0;border-bottom:none}dl dt[class],nav li[class]{list-style:none;text-indent:-1em;margin-bottom:.5em}nav li[class]{padding-left:2.5em}.case,.enumeration_case{--background-image:var(--icon-case);--link:var(--system-teal)}.class{--background-image:var(--icon-class);--link:var(--system-indigo)}.enumeration{--background-image:var(--icon-enumeration)}.enumeration,.extension{--link:var(--system-orange)}.extension{--background-image:var(--icon-extension)}.function{--background-image:var(--icon-function);--link:var(--system-green)}.initializer,.method{--background-image:var(--icon-method);--link:var(--system-blue)}.property{--background-image:var(--icon-property);--link:var(--system-teal)}.protocol{--background-image:var(--icon-protocol);--link:var(--system-pink)}.structure{--background-image:var(--icon-structure);--link:var(--system-purple)}.typealias{--background-image:var(--icon-typealias)}.typealias,.variable{--link:var(--system-green)}.variable{--background-image:var(--icon-variable)}.unknown{--link:var(--quaternary-label);color:#007aff;color:var(--link)}
\ No newline at end of file
diff --git a/Documentation/index.html b/Documentation/index.html
index ece4a00..9b2d3ac 100755
--- a/Documentation/index.html
+++ b/Documentation/index.html
@@ -4,1178 +4,7 @@
MultipeerKit - MultipeerKit
-
+
@@ -1207,7 +36,7 @@ On This Page
Classes
-
-
+
MultipeerDataSource
@@ -1215,7 +44,7 @@ Classes
-
-
+
MultipeerTransceiver
@@ -1229,7 +58,7 @@ Classes
Structures
-
-
+
Peer
@@ -1238,7 +67,7 @@ Structures
-
-
+
MultipeerConfiguration
@@ -1247,7 +76,7 @@ Structures
-
-
+
MultipeerConfiguration.Security
@@ -1261,7 +90,7 @@ Structures
Enumerations
-
-
+
MultipeerConfiguration.Invitation
@@ -1278,7 +107,7 @@ Enumerations
diff --git a/README.md b/README.md
index 55a2b53..1ea415f 100644
--- a/README.md
+++ b/README.md
@@ -22,8 +22,8 @@ let transceiver = MultipeerTransceiver()
transceiver.resume()
// Configure message receivers
-transceiver.receive(SomeCodableThing.self) { payload in
- print("Got my thing! \(payload)")
+transceiver.receive(SomeCodableThing.self) { payload, sender in
+print("Got my thing from \(sender.name)! \(payload)")
}
// Broadcast message to peers
@@ -45,4 +45,4 @@ let package = Package(
],
...
)
-```
\ No newline at end of file
+```
diff --git a/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift b/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift
index f6e257b..7e58550 100644
--- a/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift
+++ b/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift
@@ -1,8 +1,14 @@
import Foundation
+import MultipeerConnectivity.MCPeerID
final class MockMultipeerConnection: MultipeerProtocol {
- var didReceiveData: ((Data, PeerName) -> Void)?
+ let localPeer: Peer = {
+ let underlyingPeer = MCPeerID(displayName: "MockPeer")
+ return try! Peer(peer: underlyingPeer, discoveryInfo: nil)
+ }()
+
+ var didReceiveData: ((Data, Peer) -> Void)?
var didFindPeer: ((Peer) -> Void)?
var didLosePeer: ((Peer) -> Void)?
var didConnectToPeer: ((Peer) -> Void)?
@@ -19,7 +25,7 @@ final class MockMultipeerConnection: MultipeerProtocol {
}
func broadcast(_ data: Data) throws {
- didReceiveData?(data, "MockPeer")
+ didReceiveData?(data, localPeer)
}
func send(_ data: Data, to peers: [Peer]) throws {
@@ -31,7 +37,7 @@ final class MockMultipeerConnection: MultipeerProtocol {
}
func getLocalPeerId() -> String? {
- return "MockId"
+ return localPeer.id
}
}
diff --git a/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift b/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift
index a535eb5..890802f 100644
--- a/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift
+++ b/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift
@@ -27,6 +27,8 @@
import Foundation
struct MultipeerMessage: Codable {
+ static let senderUserInfoKey = CodingUserInfoKey(rawValue: "sender")!
+
let type: String
let payload: Any?
@@ -40,17 +42,17 @@ struct MultipeerMessage: Codable {
case payload
}
- private typealias MessageDecoder = (KeyedDecodingContainer) throws -> Any
+ private typealias MessageDecoder = (KeyedDecodingContainer, Peer) throws -> Any
private typealias MessageEncoder = (Any, inout KeyedEncodingContainer) throws -> Void
private static var decoders: [String: MessageDecoder] = [:]
private static var encoders: [String: MessageEncoder] = [:]
- static func register(_ type: T.Type, for typeName: String, closure: @escaping (T) -> Void) {
- decoders[typeName] = { container in
+ static func register(_ type: T.Type, for typeName: String, closure: @escaping (T, Peer) -> Void) {
+ decoders[typeName] = { container, peer in
let payload = try container.decode(T.self, forKey: .payload)
- DispatchQueue.main.async { closure(payload) }
+ DispatchQueue.main.async { closure(payload, peer) }
return payload
}
@@ -67,9 +69,11 @@ struct MultipeerMessage: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
type = try container.decode(String.self, forKey: .type)
+
+ let sender = decoder.userInfo[MultipeerMessage.senderUserInfoKey]! as! Peer
if let decode = Self.decoders[type] {
- payload = try decode(container)
+ payload = try decode(container, sender)
} else {
payload = nil
}
diff --git a/Sources/MultipeerKit/Internal API/MultipeerConnection.swift b/Sources/MultipeerKit/Internal API/MultipeerConnection.swift
index 0ed0bfe..e8420a0 100644
--- a/Sources/MultipeerKit/Internal API/MultipeerConnection.swift
+++ b/Sources/MultipeerKit/Internal API/MultipeerConnection.swift
@@ -27,7 +27,7 @@ final class MultipeerConnection: NSObject, MultipeerProtocol {
self.me = MCPeerID.fetchOrCreate(with: configuration)
}
- var didReceiveData: ((Data, PeerName) -> Void)?
+ var didReceiveData: ((Data, Peer) -> Void)?
var didFindPeer: ((Peer) -> Void)?
var didLosePeer: ((Peer) -> Void)?
var didConnectToPeer: ((Peer) -> Void)?
@@ -145,7 +145,11 @@ extension MultipeerConnection: MCSessionDelegate {
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
os_log("%{public}@", log: log, type: .debug, #function)
- didReceiveData?(data, peerID.displayName)
+ if let peer = try? Peer(peer: peerID, discoveryInfo: nil) {
+ didReceiveData?(data, peer)
+ } else {
+ os_log("Received data, but cannot create peer for %s", log: log, type: .error, #function, peerID.displayName)
+ }
}
func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {
diff --git a/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift b/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift
index cab54b9..97f63b5 100644
--- a/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift
+++ b/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift
@@ -4,7 +4,7 @@ typealias PeerName = String
protocol MultipeerProtocol: AnyObject {
- var didReceiveData: ((Data, PeerName) -> Void)? { get set }
+ var didReceiveData: ((Data, Peer) -> Void)? { get set }
var didFindPeer: ((Peer) -> Void)? { get set }
var didLosePeer: ((Peer) -> Void)? { get set }
var didConnectToPeer: ((Peer) -> Void)? { get set }
diff --git a/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift b/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift
index 2b0828d..0ab3447 100644
--- a/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift
+++ b/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift
@@ -74,12 +74,13 @@ public final class MultipeerTransceiver {
/// - type: The `Codable` type to receive.
/// - closure: The closure that will be called whenever a payload of the specified type is received.
/// - payload: The payload decoded from the remote message.
+ /// - sender: The remote peer who sent the message.
///
/// MultipeerKit communicates data between peers as JSON-encoded payloads which originate with
/// `Codable` entities. You register a closure to handle each specific type of entity,
/// and this closure is automatically called by the framework when a remote peer sends
/// a message containing an entity that decodes to the specified type.
- public func receive(_ type: T.Type, using closure: @escaping (_ payload: T) -> Void) {
+ public func receive(_ type: T.Type, using closure: @escaping (_ payload: T, _ sender: Peer) -> Void) {
MultipeerMessage.register(type, for: String(describing: type), closure: closure)
}
@@ -127,11 +128,13 @@ public final class MultipeerTransceiver {
}
}
- private func handleDataReceived(_ data: Data, from peer: PeerName) {
+ private func handleDataReceived(_ data: Data, from peer: Peer) {
os_log("%{public}@", log: log, type: .debug, #function)
do {
- let message = try JSONDecoder().decode(MultipeerMessage.self, from: data)
+ let decoder = JSONDecoder()
+ decoder.userInfo[MultipeerMessage.senderUserInfoKey] = peer
+ let message = try decoder.decode(MultipeerMessage.self, from: data)
os_log("Received message %@", log: self.log, type: .debug, String(describing: message))
} catch {
diff --git a/Tests/MultipeerKitTests/MultipeerKitTests.swift b/Tests/MultipeerKitTests/MultipeerKitTests.swift
index 6e993a8..4cdbc8d 100644
--- a/Tests/MultipeerKitTests/MultipeerKitTests.swift
+++ b/Tests/MultipeerKitTests/MultipeerKitTests.swift
@@ -36,8 +36,9 @@ final class MultipeerKitTests: XCTestCase {
let expect = XCTestExpectation(description: "Receive payload")
- mock.receive(TestPayload.self) { p in
- XCTAssertEqual(p, tsPayload)
+ mock.receive(TestPayload.self) { payload, sender in
+ XCTAssertEqual(payload, tsPayload)
+ XCTAssertEqual(sender.id, mock.localPeerId!)
expect.fulfill()
}
diff --git a/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift b/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift
index 9f0143c..9de1890 100644
--- a/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift
+++ b/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift
@@ -24,10 +24,10 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
let t = MultipeerTransceiver(configuration: config)
- t.receive(ExamplePayload.self) { [weak self] payload in
+ t.receive(ExamplePayload.self) { [weak self] payload, peer in
print("Got payload: \(payload)")
- self?.notify(with: payload)
+ self?.notify(with: payload, peer: peer)
}
return t
@@ -37,9 +37,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
MultipeerDataSource(transceiver: transceiver)
}()
- private func notify(with payload: ExamplePayload) {
+ private func notify(with payload: ExamplePayload, peer: Peer) {
let content = UNMutableNotificationContent()
- content.body = payload.message
+ content.body = "\"\(payload.message)\" from \(peer.name)"
let request = UNNotificationRequest(identifier: payload.message, content: content, trigger: nil)
UNUserNotificationCenter.current().add(request) { _ in
Properties
-
identity
@@ -1247,17 +85,17 @@ The first object in this array should be a SecIdentity
object that provides the local peer’s identity.
The remainder of the array should contain zero or more additional SecCertificate objects that provide any +
The first object in this array should be a SecIdentity
object that provides the local peer’s identity.
The remainder of the array should contain zero or more additional SecCertificate objects that provide any intermediate certificates that nearby peers might require when verifying the local peer’s identity. These certificates should be sent in certificate chain order.
- -Check Apple's MCSession
docs for more information.
Check Apple's MCSession
docs for more information.
encryptionPreference
@@ -1267,7 +105,7 @@
invitationHandler
@@ -1277,15 +115,15 @@ It receives the Peer
that sent the invitation, a custom Data
value
+
It receives the Peer
that sent the invitation, a custom Data
value
that's a context that can be used to customize the invitation,
and a closure to be called with true
to accept the invitation or false
to reject it.
The default implementation accepts all invitations.
- + +The default implementation accepts all invitations.
+
`default`
@@ -1304,7 +142,7 @@
diff --git a/Documentation/MultipeerDataSource/index.html b/Documentation/MultipeerDataSource/index.html
index 36c6795..7048ab7 100755
--- a/Documentation/MultipeerDataSource/index.html
+++ b/Documentation/MultipeerDataSource/index.html
@@ -4,1178 +4,7 @@
MultipeerKit - MultipeerDataSource
-
+
@@ -1211,8 +40,8 @@
@available(tvOS 13.0, *) @available(OSX 10.15, *) @available(iOS 13.0, *) public final class MultipeerDataSource: ObservableObject
Relationships
-
-
+
+
-
+
Peer->Identifiable
@@ -1254,7 +83,7 @@ Relationships
Hashable
-
+
Peer->Hashable
@@ -1263,18 +92,34 @@ Relationships
- Inheritance graph for Peer.
-
+ Inheritance graph for Peer.
+
Conforms To
Hashable
Identifiable
+
+ Initializers
+
+
+
+ init(peer:discoveryInfo:)
+
+ init(peer: MCPeerID, discoveryInfo: [String: String]?) throws
+
+
Properties
-
+
+
+ underlyingPeer
+
+ let underlyingPeer: MCPeerID
+
+
id
@@ -1284,7 +129,7 @@
-
+
name
@@ -1294,7 +139,7 @@
-
+
discoveryInfo
@@ -1304,7 +149,7 @@
-
+
isConnected
@@ -1323,7 +168,7 @@
diff --git a/Documentation/all.css b/Documentation/all.css
new file mode 100755
index 0000000..4e9b4a7
--- /dev/null
+++ b/Documentation/all.css
@@ -0,0 +1 @@
+:root{--system-red:#ff3b30;--system-orange:#ff9500;--system-yellow:#fc0;--system-green:#34c759;--system-teal:#5ac8fa;--system-blue:#007aff;--system-indigo:#5856d6;--system-purple:#af52de;--system-pink:#ff2d55;--system-gray:#8e8e93;--system-gray2:#aeaeb2;--system-gray3:#c7c7cc;--system-gray4:#d1d1d6;--system-gray5:#e5e5ea;--system-gray6:#f2f2f7;--label:#000;--secondary-label:#3c3c43;--tertiary-label:#48484a;--quaternary-label:#636366;--placeholder-text:#8e8e93;--link:#007aff;--separator:#e5e5ea;--opaque-separator:#c6c6c8;--system-fill:#787880;--secondary-system-fill:#787880;--tertiary-system-fill:#767680;--quaternary-system-fill:#747480;--system-background:#fff;--secondary-system-background:#f2f2f7;--tertiary-system-background:#fff;--system-grouped-background:#f2f2f7;--secondary-system-grouped-background:#fff;--tertiary-system-grouped-background:#f2f2f7}@supports (color:color(display-p3 1 1 1)){:root{--system-red:color(display-p3 1 0.2314 0.1882);--system-orange:color(display-p3 1 0.5843 0);--system-yellow:color(display-p3 1 0.8 0);--system-green:color(display-p3 0.2039 0.7804 0.349);--system-teal:color(display-p3 0.3529 0.7843 0.9804);--system-blue:color(display-p3 0 0.4784 1);--system-indigo:color(display-p3 0.3451 0.3373 0.8392);--system-purple:color(display-p3 0.6863 0.3216 0.8706);--system-pink:color(display-p3 1 0.1765 0.3333);--system-gray:color(display-p3 0.5569 0.5569 0.5765);--system-gray2:color(display-p3 0.6824 0.6824 0.698);--system-gray3:color(display-p3 0.7804 0.7804 0.8);--system-gray4:color(display-p3 0.8196 0.8196 0.8392);--system-gray5:color(display-p3 0.898 0.898 0.9176);--system-gray6:color(display-p3 0.949 0.949 0.9686);--label:color(display-p3 0 0 0);--secondary-label:color(display-p3 0.2353 0.2353 0.2627);--tertiary-label:color(display-p3 0.2823 0.2823 0.2901);--quaternary-label:color(display-p3 0.4627 0.4627 0.5019);--placeholder-text:color(display-p3 0.5568 0.5568 0.5764);--link:color(display-p3 0 0.4784 1);--separator:color(display-p3 0.898 0.898 0.9176);--opaque-separator:color(display-p3 0.7765 0.7765 0.7843);--system-fill:color(display-p3 0.4706 0.4706 0.502);--secondary-system-fill:color(display-p3 0.4706 0.4706 0.502);--tertiary-system-fill:color(display-p3 0.4627 0.4627 0.502);--quaternary-system-fill:color(display-p3 0.4549 0.4549 0.502);--system-background:color(display-p3 1 1 1);--secondary-system-background:color(display-p3 0.949 0.949 0.9686);--tertiary-system-background:color(display-p3 1 1 1);--system-grouped-background:color(display-p3 0.949 0.949 0.9686);--secondary-system-grouped-background:color(display-p3 1 1 1);--tertiary-system-grouped-background:color(display-p3 0.949 0.949 0.9686)}}:root{--large-title:600 32pt/39pt sans-serif;--title-1:600 26pt/32pt sans-serif;--title-2:600 20pt/25pt sans-serif;--title-3:500 18pt/23pt sans-serif;--headline:500 15pt/20pt sans-serif;--body:300 15pt/20pt sans-serif;--callout:300 14pt/19pt sans-serif;--subhead:300 13pt/18pt sans-serif;--footnote:300 12pt/16pt sans-serif;--caption-1:300 11pt/13pt sans-serif;--caption-2:300 11pt/13pt sans-serif;--icon-case:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%2389c5e6' height='90' rx='8' stroke='%236bb7e1' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M20.21 50c0-20.7 11.9-32.79 30.8-32.79 16 0 28.21 10.33 28.7 25.32H64.19C63.4 35 58.09 30.11 51 30.11c-8.79 0-14.37 7.52-14.37 19.82s5.54 20 14.41 20c7.08 0 12.22-4.66 13.23-12.09h15.52c-.74 15.07-12.43 25-28.78 25C32 82.81 20.21 70.72 20.21 50z' fill='%23fff'/%3E%3C/svg%3E");--icon-class:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%239b98e6' height='90' rx='8' stroke='%235856d6' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='m20.21 50c0-20.7 11.9-32.79 30.8-32.79 16 0 28.21 10.33 28.7 25.32h-15.52c-.79-7.53-6.1-12.42-13.19-12.42-8.79 0-14.37 7.52-14.37 19.82s5.54 20 14.41 20c7.08 0 12.22-4.66 13.23-12.09h15.52c-.74 15.07-12.43 25-28.78 25-19.01-.03-30.8-12.12-30.8-32.84z' fill='%23fff'/%3E%3C/svg%3E");--icon-enumeration:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23eca95b' height='90' rx='8' stroke='%23e89234' stroke-miterlimit='10' stroke-width='4' width='90' x='5.17' y='5'/%3E%3Cpath d='M71.9 81.71H28.43V18.29H71.9v13H44.56v12.62h25.71v11.87H44.56V68.7H71.9z' fill='%23fff'/%3E%3C/svg%3E");--icon-extension:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23eca95b' height='90' rx='8' stroke='%23e89234' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cg fill='%23fff'%3E%3Cpath d='M54.43 81.93H20.51V18.07h33.92v12.26H32.61v13.8h20.45v11.32H32.61v14.22h21.82zM68.74 74.58h-.27l-2.78 7.35h-7.28L64 69.32l-6-12.54h8l2.74 7.3h.27l2.76-7.3h7.64l-6.14 12.54 5.89 12.61h-7.64z'/%3E%3C/g%3E%3C/svg%3E");--icon-function:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M24.25 75.66A5.47 5.47 0 0130 69.93c1.55 0 3.55.41 6.46.41 3.19 0 4.78-1.55 5.46-6.65l1.5-10.14h-9.34a6 6 0 110-12h11.1l1.09-7.27C47.82 23.39 54.28 17.7 64 17.7c6.69 0 11.74 1.77 11.74 6.64A5.47 5.47 0 0170 30.07c-1.55 0-3.55-.41-6.46-.41-3.14 0-4.73 1.51-5.46 6.65l-.78 5.27h11.44a6 6 0 11.05 12H55.6l-1.78 12.11C52.23 76.61 45.72 82.3 36 82.3c-6.7 0-11.75-1.77-11.75-6.64z' fill='%23fff'/%3E%3C/svg%3E");--icon-method:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%235a98f8' height='90' rx='8' stroke='%232974ed' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M70.61 81.71v-39.6h-.31l-15.69 39.6h-9.22l-15.65-39.6h-.35v39.6H15.2V18.29h18.63l16 41.44h.36l16-41.44H84.8v63.42z' fill='%23fff'/%3E%3C/svg%3E");--icon-property:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%2389c5e6' height='90' rx='8' stroke='%236bb7e1' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M52.31 18.29c13.62 0 22.85 8.84 22.85 22.46s-9.71 22.37-23.82 22.37H41v18.59H24.84V18.29zM41 51h7c6.85 0 10.89-3.56 10.89-10.2S54.81 30.64 48 30.64h-7z' fill='%23fff'/%3E%3C/svg%3E");--icon-protocol:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23ff6682' height='90' rx='8' stroke='%23ff2d55' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cg fill='%23fff'%3E%3Cpath d='M46.28 18.29c11.84 0 20 8.66 20 21.71s-8.44 21.71-20.6 21.71H34.87v20H22.78V18.29zM34.87 51.34H43c6.93 0 11-4 11-11.29S50 28.8 43.07 28.8h-8.2zM62 57.45h8v4.77h.16c.84-3.45 2.54-5.12 5.17-5.12a5.06 5.06 0 011.92.35V65a5.69 5.69 0 00-2.39-.51c-3.08 0-4.66 1.74-4.66 5.12v12.1H62z'/%3E%3C/g%3E%3C/svg%3E");--icon-structure:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23b57edf' height='90' rx='8' stroke='%239454c2' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M38.38 63c.74 4.53 5.62 7.16 11.82 7.16s10.37-2.81 10.37-6.68c0-3.51-2.73-5.31-10.24-6.76l-6.5-1.23C31.17 53.14 24.62 47 24.62 37.28c0-12.22 10.59-20.09 25.18-20.09 16 0 25.36 7.83 25.53 19.91h-15c-.26-4.57-4.57-7.29-10.42-7.29s-9.31 2.63-9.31 6.37c0 3.34 2.9 5.18 9.8 6.5l6.5 1.23C70.46 46.51 76.61 52 76.61 62c0 12.74-10 20.83-26.72 20.83-15.82 0-26.28-7.3-26.5-19.78z' fill='%23fff'/%3E%3C/svg%3E");--icon-typealias:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M42 81.71V31.3H24.47v-13h51.06v13H58v50.41z' fill='%23fff'/%3E%3C/svg%3E");--icon-variable:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M39.85 81.71L19.63 18.29H38l12.18 47.64h.35L62.7 18.29h17.67L60.15 81.71z' fill='%23fff'/%3E%3C/svg%3E")}body,button,input,select,textarea{-moz-font-feature-settings:"kern";-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;direction:ltr;font-synthesis:none;text-align:left}h1:first-of-type,h2:first-of-type,h3:first-of-type,h4:first-of-type,h5:first-of-type,h6:first-of-type{margin-top:0}h1 code,h2 code,h3 code,h4 code,h5 code,h6 code{font-family:inherit;font-weight:inherit}h1 img,h2 img,h3 img,h4 img,h5 img,h6 img{margin:0 .5em .2em 0;vertical-align:middle;display:inline-block}h1+*,h2+*,h3+*,h4+*,h5+*,h6+*{margin-top:.8em}img+h1{margin-top:.5em}img+h1,img+h2,img+h3,img+h4,img+h5,img+h6{margin-top:.3em}:is(h1,h2,h3,h4,h5,h6)+:is(h1,h2,h3,h4,h5,h6){margin-top:.4em}:matches(h1,h2,h3,h4,h5,h6)+:matches(h1,h2,h3,h4,h5,h6){margin-top:.4em}:is(p,ul,ol)+:is(h1,h2,h3,h4,h5,h6){margin-top:1.6em}:matches(p,ul,ol)+:matches(h1,h2,h3,h4,h5,h6){margin-top:1.6em}:is(p,ul,ol)+*{margin-top:.8em}:matches(p,ul,ol)+*{margin-top:.8em}ol,ul{margin-left:1.17647em}:matches(ul,ol) :matches(ul,ol){margin-bottom:0;margin-top:0}nav h2{color:#3c3c43;color:var(--secondary-label);font-size:1rem;font-feature-settings:"c2sc";font-variant:small-caps;font-weight:600;text-transform:uppercase}nav ol,nav ul{margin:0;list-style:none}nav li li{font-size:smaller}a:link,a:visited{text-decoration:none}a:hover{text-decoration:underline}a:active{text-decoration:none}a+a{display:inline-block}b,strong{font-weight:600}.discussion,.summary{font:300 14pt/19pt sans-serif;font:var(--callout)}article>.discussion{margin-bottom:2em}.discussion .highlight{background:transparent;border:1px solid #e5e5ea;border:1px solid var(--separator);font:300 11pt/13pt sans-serif;font:var(--caption-1);padding:1em;text-indent:0}cite,dfn,em,i{font-style:italic}:matches(h1,h2,h3) sup{font-size:.4em}sup a{color:inherit;vertical-align:inherit}sup a:hover{color:#007aff;color:var(--link);text-decoration:none}sub{line-height:1}abbr{border:0}:lang(ja),:lang(ko),:lang(th),:lang(zh){font-style:normal}:lang(ko){word-break:keep-all}form fieldset{margin:1em auto;max-width:450px;width:95%}form label{display:block;font-size:1em;font-weight:400;line-height:1.5em;margin-bottom:14px;position:relative;width:100%}input[type=email],input[type=number],input[type=password],input[type=tel],input[type=text],input[type=url],textarea{border-radius:4px;border:1px solid #e5e5ea;border:1px solid var(--separator);color:#333;font-family:inherit;font-size:100%;font-weight:400;height:34px;margin:0;padding:0 1em;position:relative;vertical-align:top;width:100%;z-index:1}input[type=email],input [type=email]:focus,input[type=number],input [type=number]:focus,input[type=password],input [type=password]:focus,input[type=tel],input [type=tel]:focus,input[type=text],input [type=text]:focus,input[type=url],input [type=url]:focus,textarea,textarea:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}input[type=email]:focus,input[type=number]:focus,input[type=password]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=url]:focus,textarea:focus{border-color:#08c;box-shadow:0 0 0 3px rgba(0,136,204,.3);outline:0;z-index:9}input[type=email]:-moz-read-only,input[type=number]:-moz-read-only,input[type=password]:-moz-read-only,input[type=tel]:-moz-read-only,input[type=text]:-moz-read-only,input[type=url]:-moz-read-only,textarea:-moz-read-only{background:none;border:none;box-shadow:none;padding-left:0}input[type=email]:read-only,input[type=number]:read-only,input[type=password]:read-only,input[type=tel]:read-only,input[type=text]:read-only,input[type=url]:read-only,textarea:read-only{background:none;border:none;box-shadow:none;padding-left:0}::-webkit-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::-moz-placeholder{color:#8e8e93;color:var(--placeholder-text)}:-ms-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::-ms-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::placeholder{color:#8e8e93;color:var(--placeholder-text)}textarea{-webkit-overflow-scrolling:touch;line-height:1.4737;min-height:134px;overflow-y:auto;resize:vertical;transform:translateZ(0)}textarea,textarea:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}select{background:transparent;border-radius:4px;border:none;cursor:pointer;font-family:inherit;font-size:1em;height:34px;margin:0;padding:0 1em;width:100%}select,select:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}select:focus{border-color:#08c;box-shadow:0 0 0 3px rgba(0,136,204,.3);outline:0;z-index:9}input[type=file]{background:#fafafa;border-radius:4px;color:#333;cursor:pointer;font-family:inherit;font-size:100%;height:34px;margin:0;padding:6px 1em;position:relative;vertical-align:top;width:100%;z-index:1}input[type=file]:focus{border-color:#08c;outline:0;box-shadow:0 0 0 3px rgba(0,136,204,.3);z-index:9}button,button:focus,input[type=file]:focus,input[type=file]:focus:focus,input[type=reset],input[type=reset]:focus,input[type=submit],input[type=submit]:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}:matches(button,input[type=reset],input[type=submit]){background-color:#e3e3e3;background:linear-gradient(#fff,#e3e3e3);border-color:#d6d6d6;color:#0070c9}:matches(button,input[type=reset],input[type=submit]):hover{background-color:#eee;background:linear-gradient(#fff,#eee);border-color:#d9d9d9}:matches(button,input[type=reset],input[type=submit]):active{background-color:#dcdcdc;background:linear-gradient(#f7f7f7,#dcdcdc);border-color:#d0d0d0}:matches(button,input[type=reset],input[type=submit]):disabled{background-color:#e3e3e3;background:linear-gradient(#fff,#e3e3e3);border-color:#d6d6d6;color:#0070c9}body{background:#f2f2f7;background:var(--system-grouped-background);color:#000;color:var(--label);font-family:ui-system,-apple-system,BlinkMacSystemFont,sans-serif;font:300 15pt/20pt sans-serif;font:var(--body)}h1{font:600 32pt/39pt sans-serif;font:var(--large-title)}h2{font:600 20pt/25pt sans-serif;font:var(--title-2)}h3{font:500 18pt/23pt sans-serif;font:var(--title-3)}h4,h5,h6{font:500 15pt/20pt sans-serif;font:var(--headline)}a{color:#007aff;color:var(--link)}label{font:300 14pt/19pt sans-serif;font:var(--callout)}input,label{display:block}input{margin-bottom:1em}hr{border:none;border-top:1px solid #e5e5ea;border-top:1px solid var(--separator);margin:1em 0}table{width:100%;font:300 11pt/13pt sans-serif;font:var(--caption-1);caption-side:bottom;margin-bottom:2em}td,th{padding:0 1em}th{font-weight:600;text-align:left}thead th{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator)}tr:last-of-type td,tr:last-of-type th{border-bottom:none}td,th{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);color:#3c3c43;color:var(--secondary-label)}caption{color:#48484a;color:var(--tertiary-label);font:300 11pt/13pt sans-serif;font:var(--caption-2);margin-top:2em;text-align:left}.graph text,code{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-weight:300}.graph>polygon{display:none}.graph text{fill:currentColor!important}.graph ellipse,.graph path,.graph polygon,.graph rect{stroke:currentColor!important}body{width:90vw;max-width:1280px;margin:1em auto}body>header{font:600 26pt/32pt sans-serif;font:var(--title-1);padding:.5em 0}body>header a{color:#000;color:var(--label)}body>header span{font-weight:400}body>header sup{text-transform:uppercase;font-size:small;font-weight:300;letter-spacing:.1ch}body>footer,body>header sup{color:#3c3c43;color:var(--secondary-label)}body>footer{clear:both;padding:1em 0;font:300 11pt/13pt sans-serif;font:var(--caption-1)}@media screen and (max-width:768px){body{width:96vw;max-width:100%}body>header{font:500 18pt/23pt sans-serif;font:var(--title-3);text-align:left;padding:1em 0}body>nav{display:none}body>main{padding:0 1em}}@media screen and (max-width:768px){#relationships figure{display:none}section>[role=article][class] pre{margin-left:-2.5em}section>[role=article][class] div{margin-left:-2em}}main,nav{overflow-x:scroll}main{background:#fff;background:var(--system-background);border-radius:8px;padding:0 2em}main section{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);margin-bottom:2em;padding-bottom:1em}main section:last-of-type{border-bottom:none;margin-bottom:0}nav{float:right;margin-left:1em;max-height:100vh;overflow:scroll;padding:0 1em 3em;position:-webkit-sticky;position:sticky;top:1em;width:20vw}nav a{color:#3c3c43;color:var(--secondary-label)}nav ul a{color:#48484a;color:var(--tertiary-label)}nav ol,nav ul{padding:0}nav ul{font:300 14pt/19pt sans-serif;font:var(--callout);margin-bottom:1em}nav ol>li>a{display:block;font-size:smaller;font:500 15pt/20pt sans-serif;font:var(--headline);margin:.5em 0}nav li{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}blockquote{--link:var(--secondary-label);border-left:4px solid #e5e5ea;border-left:4px solid var(--separator);color:#3c3c43;color:var(--secondary-label);font-size:smaller;margin-left:0;padding-left:2em}blockquote a{text-decoration:underline}article{padding:2em 0 1em}article>.summary{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);margin-bottom:2em;padding-bottom:1em}article>.summary:last-child{border-bottom:none}.parameters th{text-align:right}.parameters td{color:#3c3c43;color:var(--secondary-label)}.parameters th+td{text-align:center}dl{padding-top:1em}dt{font:500 15pt/20pt sans-serif;font:var(--headline)}dd{margin-left:2em;margin-bottom:1em}dd p{margin-top:0}.highlight{background:#f2f2f7;background:var(--secondary-system-background);border-radius:8px;font-size:smaller;margin-bottom:2em;overflow-x:scroll;padding:1em 1em 1em 3em;text-indent:-2em;white-space:pre-line}.highlight .p{white-space:nowrap}.highlight .placeholder{color:#000;color:var(--label)}.highlight a{text-decoration:underline;color:#8e8e93;color:var(--placeholder-text)}.highlight .attribute,.highlight .keyword,.highlight .literal{color:#af52de;color:var(--system-purple)}.highlight .number{color:#007aff;color:var(--system-blue)}.highlight .declaration{color:#5ac8fa;color:var(--system-teal)}.highlight .type{color:#5856d6;color:var(--system-indigo)}.highlight .directive{color:#ff9500;color:var(--system-orange)}.highlight .comment{color:#8e8e93;color:var(--system-gray)}main summary:hover{text-decoration:underline}figure{margin:2em 0;padding:1em 0}figure svg{max-width:100%;height:auto!important;margin:0 auto;display:block}h1 small{font-size:.5em;line-height:1.5;display:block;font-weight:400;color:#636366;color:var(--quaternary-label)}dd code,li code,p code{font-size:smaller;color:#3c3c43;color:var(--secondary-label)}a code{text-decoration:underline}dl dt[class],nav li[class],section>[role=article][class]{background-image:var(--background-image);background-size:1em;background-repeat:no-repeat;background-position:left .25em;padding-left:3em}dl dt[class]{background-position-y:.125em}section>[role=article]{margin-bottom:1em;padding-bottom:1em;border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);padding-left:2em!important}section>[role=article]:last-of-type{margin-bottom:0;padding-bottom:0;border-bottom:none}dl dt[class],nav li[class]{list-style:none;text-indent:-1em;margin-bottom:.5em}nav li[class]{padding-left:2.5em}.case,.enumeration_case{--background-image:var(--icon-case);--link:var(--system-teal)}.class{--background-image:var(--icon-class);--link:var(--system-indigo)}.enumeration{--background-image:var(--icon-enumeration)}.enumeration,.extension{--link:var(--system-orange)}.extension{--background-image:var(--icon-extension)}.function{--background-image:var(--icon-function);--link:var(--system-green)}.initializer,.method{--background-image:var(--icon-method);--link:var(--system-blue)}.property{--background-image:var(--icon-property);--link:var(--system-teal)}.protocol{--background-image:var(--icon-protocol);--link:var(--system-pink)}.structure{--background-image:var(--icon-structure);--link:var(--system-purple)}.typealias{--background-image:var(--icon-typealias)}.typealias,.variable{--link:var(--system-green)}.variable{--background-image:var(--icon-variable)}.unknown{--link:var(--quaternary-label);color:#007aff;color:var(--link)}
\ No newline at end of file
diff --git a/Documentation/index.html b/Documentation/index.html
index ece4a00..9b2d3ac 100755
--- a/Documentation/index.html
+++ b/Documentation/index.html
@@ -4,1178 +4,7 @@
MultipeerKit - MultipeerKit
-
+
@@ -1207,7 +36,7 @@ On This Page
Classes
-
-
+
MultipeerDataSource
@@ -1215,7 +44,7 @@ Classes
-
-
+
MultipeerTransceiver
@@ -1229,7 +58,7 @@ Classes
Structures
-
-
+
Peer
@@ -1238,7 +67,7 @@ Structures
-
-
+
MultipeerConfiguration
@@ -1247,7 +76,7 @@ Structures
-
-
+
MultipeerConfiguration.Security
@@ -1261,7 +90,7 @@ Structures
Enumerations
-
-
+
MultipeerConfiguration.Invitation
@@ -1278,7 +107,7 @@ Enumerations
diff --git a/README.md b/README.md
index 55a2b53..1ea415f 100644
--- a/README.md
+++ b/README.md
@@ -22,8 +22,8 @@ let transceiver = MultipeerTransceiver()
transceiver.resume()
// Configure message receivers
-transceiver.receive(SomeCodableThing.self) { payload in
- print("Got my thing! \(payload)")
+transceiver.receive(SomeCodableThing.self) { payload, sender in
+print("Got my thing from \(sender.name)! \(payload)")
}
// Broadcast message to peers
@@ -45,4 +45,4 @@ let package = Package(
],
...
)
-```
\ No newline at end of file
+```
diff --git a/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift b/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift
index f6e257b..7e58550 100644
--- a/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift
+++ b/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift
@@ -1,8 +1,14 @@
import Foundation
+import MultipeerConnectivity.MCPeerID
final class MockMultipeerConnection: MultipeerProtocol {
- var didReceiveData: ((Data, PeerName) -> Void)?
+ let localPeer: Peer = {
+ let underlyingPeer = MCPeerID(displayName: "MockPeer")
+ return try! Peer(peer: underlyingPeer, discoveryInfo: nil)
+ }()
+
+ var didReceiveData: ((Data, Peer) -> Void)?
var didFindPeer: ((Peer) -> Void)?
var didLosePeer: ((Peer) -> Void)?
var didConnectToPeer: ((Peer) -> Void)?
@@ -19,7 +25,7 @@ final class MockMultipeerConnection: MultipeerProtocol {
}
func broadcast(_ data: Data) throws {
- didReceiveData?(data, "MockPeer")
+ didReceiveData?(data, localPeer)
}
func send(_ data: Data, to peers: [Peer]) throws {
@@ -31,7 +37,7 @@ final class MockMultipeerConnection: MultipeerProtocol {
}
func getLocalPeerId() -> String? {
- return "MockId"
+ return localPeer.id
}
}
diff --git a/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift b/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift
index a535eb5..890802f 100644
--- a/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift
+++ b/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift
@@ -27,6 +27,8 @@
import Foundation
struct MultipeerMessage: Codable {
+ static let senderUserInfoKey = CodingUserInfoKey(rawValue: "sender")!
+
let type: String
let payload: Any?
@@ -40,17 +42,17 @@ struct MultipeerMessage: Codable {
case payload
}
- private typealias MessageDecoder = (KeyedDecodingContainer) throws -> Any
+ private typealias MessageDecoder = (KeyedDecodingContainer, Peer) throws -> Any
private typealias MessageEncoder = (Any, inout KeyedEncodingContainer) throws -> Void
private static var decoders: [String: MessageDecoder] = [:]
private static var encoders: [String: MessageEncoder] = [:]
- static func register(_ type: T.Type, for typeName: String, closure: @escaping (T) -> Void) {
- decoders[typeName] = { container in
+ static func register(_ type: T.Type, for typeName: String, closure: @escaping (T, Peer) -> Void) {
+ decoders[typeName] = { container, peer in
let payload = try container.decode(T.self, forKey: .payload)
- DispatchQueue.main.async { closure(payload) }
+ DispatchQueue.main.async { closure(payload, peer) }
return payload
}
@@ -67,9 +69,11 @@ struct MultipeerMessage: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
type = try container.decode(String.self, forKey: .type)
+
+ let sender = decoder.userInfo[MultipeerMessage.senderUserInfoKey]! as! Peer
if let decode = Self.decoders[type] {
- payload = try decode(container)
+ payload = try decode(container, sender)
} else {
payload = nil
}
diff --git a/Sources/MultipeerKit/Internal API/MultipeerConnection.swift b/Sources/MultipeerKit/Internal API/MultipeerConnection.swift
index 0ed0bfe..e8420a0 100644
--- a/Sources/MultipeerKit/Internal API/MultipeerConnection.swift
+++ b/Sources/MultipeerKit/Internal API/MultipeerConnection.swift
@@ -27,7 +27,7 @@ final class MultipeerConnection: NSObject, MultipeerProtocol {
self.me = MCPeerID.fetchOrCreate(with: configuration)
}
- var didReceiveData: ((Data, PeerName) -> Void)?
+ var didReceiveData: ((Data, Peer) -> Void)?
var didFindPeer: ((Peer) -> Void)?
var didLosePeer: ((Peer) -> Void)?
var didConnectToPeer: ((Peer) -> Void)?
@@ -145,7 +145,11 @@ extension MultipeerConnection: MCSessionDelegate {
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
os_log("%{public}@", log: log, type: .debug, #function)
- didReceiveData?(data, peerID.displayName)
+ if let peer = try? Peer(peer: peerID, discoveryInfo: nil) {
+ didReceiveData?(data, peer)
+ } else {
+ os_log("Received data, but cannot create peer for %s", log: log, type: .error, #function, peerID.displayName)
+ }
}
func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {
diff --git a/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift b/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift
index cab54b9..97f63b5 100644
--- a/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift
+++ b/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift
@@ -4,7 +4,7 @@ typealias PeerName = String
protocol MultipeerProtocol: AnyObject {
- var didReceiveData: ((Data, PeerName) -> Void)? { get set }
+ var didReceiveData: ((Data, Peer) -> Void)? { get set }
var didFindPeer: ((Peer) -> Void)? { get set }
var didLosePeer: ((Peer) -> Void)? { get set }
var didConnectToPeer: ((Peer) -> Void)? { get set }
diff --git a/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift b/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift
index 2b0828d..0ab3447 100644
--- a/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift
+++ b/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift
@@ -74,12 +74,13 @@ public final class MultipeerTransceiver {
/// - type: The `Codable` type to receive.
/// - closure: The closure that will be called whenever a payload of the specified type is received.
/// - payload: The payload decoded from the remote message.
+ /// - sender: The remote peer who sent the message.
///
/// MultipeerKit communicates data between peers as JSON-encoded payloads which originate with
/// `Codable` entities. You register a closure to handle each specific type of entity,
/// and this closure is automatically called by the framework when a remote peer sends
/// a message containing an entity that decodes to the specified type.
- public func receive(_ type: T.Type, using closure: @escaping (_ payload: T) -> Void) {
+ public func receive(_ type: T.Type, using closure: @escaping (_ payload: T, _ sender: Peer) -> Void) {
MultipeerMessage.register(type, for: String(describing: type), closure: closure)
}
@@ -127,11 +128,13 @@ public final class MultipeerTransceiver {
}
}
- private func handleDataReceived(_ data: Data, from peer: PeerName) {
+ private func handleDataReceived(_ data: Data, from peer: Peer) {
os_log("%{public}@", log: log, type: .debug, #function)
do {
- let message = try JSONDecoder().decode(MultipeerMessage.self, from: data)
+ let decoder = JSONDecoder()
+ decoder.userInfo[MultipeerMessage.senderUserInfoKey] = peer
+ let message = try decoder.decode(MultipeerMessage.self, from: data)
os_log("Received message %@", log: self.log, type: .debug, String(describing: message))
} catch {
diff --git a/Tests/MultipeerKitTests/MultipeerKitTests.swift b/Tests/MultipeerKitTests/MultipeerKitTests.swift
index 6e993a8..4cdbc8d 100644
--- a/Tests/MultipeerKitTests/MultipeerKitTests.swift
+++ b/Tests/MultipeerKitTests/MultipeerKitTests.swift
@@ -36,8 +36,9 @@ final class MultipeerKitTests: XCTestCase {
let expect = XCTestExpectation(description: "Receive payload")
- mock.receive(TestPayload.self) { p in
- XCTAssertEqual(p, tsPayload)
+ mock.receive(TestPayload.self) { payload, sender in
+ XCTAssertEqual(payload, tsPayload)
+ XCTAssertEqual(sender.id, mock.localPeerId!)
expect.fulfill()
}
diff --git a/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift b/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift
index 9f0143c..9de1890 100644
--- a/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift
+++ b/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift
@@ -24,10 +24,10 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
let t = MultipeerTransceiver(configuration: config)
- t.receive(ExamplePayload.self) { [weak self] payload in
+ t.receive(ExamplePayload.self) { [weak self] payload, peer in
print("Got payload: \(payload)")
- self?.notify(with: payload)
+ self?.notify(with: payload, peer: peer)
}
return t
@@ -37,9 +37,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
MultipeerDataSource(transceiver: transceiver)
}()
- private func notify(with payload: ExamplePayload) {
+ private func notify(with payload: ExamplePayload, peer: Peer) {
let content = UNMutableNotificationContent()
- content.body = payload.message
+ content.body = "\"\(payload.message)\" from \(peer.name)"
let request = UNNotificationRequest(identifier: payload.message, content: content, trigger: nil)
UNUserNotificationCenter.current().add(request) { _ in
@available(tvOS 13.0, *) @available(OSX 10.15, *) @available(iOS 13.0, *) public final class MultipeerDataSource: ObservableObject
Relationships
-
-
+
+
-
+
Peer->Identifiable
@@ -1254,7 +83,7 @@ Relationships
Hashable
-
+
Peer->Hashable
@@ -1263,18 +92,34 @@ Relationships
- Inheritance graph for Peer.
-
+ Inheritance graph for Peer.
+
Conforms To
Hashable
Identifiable
+
+ Initializers
+
+
+
+ init(peer:discoveryInfo:)
+
+ init(peer: MCPeerID, discoveryInfo: [String: String]?) throws
+
+
Properties
-
+
+
+ underlyingPeer
+
+ let underlyingPeer: MCPeerID
+
+
id
@@ -1284,7 +129,7 @@
-
+
name
@@ -1294,7 +139,7 @@
-
+
discoveryInfo
@@ -1304,7 +149,7 @@
-
+
isConnected
@@ -1323,7 +168,7 @@
diff --git a/Documentation/all.css b/Documentation/all.css
new file mode 100755
index 0000000..4e9b4a7
--- /dev/null
+++ b/Documentation/all.css
@@ -0,0 +1 @@
+:root{--system-red:#ff3b30;--system-orange:#ff9500;--system-yellow:#fc0;--system-green:#34c759;--system-teal:#5ac8fa;--system-blue:#007aff;--system-indigo:#5856d6;--system-purple:#af52de;--system-pink:#ff2d55;--system-gray:#8e8e93;--system-gray2:#aeaeb2;--system-gray3:#c7c7cc;--system-gray4:#d1d1d6;--system-gray5:#e5e5ea;--system-gray6:#f2f2f7;--label:#000;--secondary-label:#3c3c43;--tertiary-label:#48484a;--quaternary-label:#636366;--placeholder-text:#8e8e93;--link:#007aff;--separator:#e5e5ea;--opaque-separator:#c6c6c8;--system-fill:#787880;--secondary-system-fill:#787880;--tertiary-system-fill:#767680;--quaternary-system-fill:#747480;--system-background:#fff;--secondary-system-background:#f2f2f7;--tertiary-system-background:#fff;--system-grouped-background:#f2f2f7;--secondary-system-grouped-background:#fff;--tertiary-system-grouped-background:#f2f2f7}@supports (color:color(display-p3 1 1 1)){:root{--system-red:color(display-p3 1 0.2314 0.1882);--system-orange:color(display-p3 1 0.5843 0);--system-yellow:color(display-p3 1 0.8 0);--system-green:color(display-p3 0.2039 0.7804 0.349);--system-teal:color(display-p3 0.3529 0.7843 0.9804);--system-blue:color(display-p3 0 0.4784 1);--system-indigo:color(display-p3 0.3451 0.3373 0.8392);--system-purple:color(display-p3 0.6863 0.3216 0.8706);--system-pink:color(display-p3 1 0.1765 0.3333);--system-gray:color(display-p3 0.5569 0.5569 0.5765);--system-gray2:color(display-p3 0.6824 0.6824 0.698);--system-gray3:color(display-p3 0.7804 0.7804 0.8);--system-gray4:color(display-p3 0.8196 0.8196 0.8392);--system-gray5:color(display-p3 0.898 0.898 0.9176);--system-gray6:color(display-p3 0.949 0.949 0.9686);--label:color(display-p3 0 0 0);--secondary-label:color(display-p3 0.2353 0.2353 0.2627);--tertiary-label:color(display-p3 0.2823 0.2823 0.2901);--quaternary-label:color(display-p3 0.4627 0.4627 0.5019);--placeholder-text:color(display-p3 0.5568 0.5568 0.5764);--link:color(display-p3 0 0.4784 1);--separator:color(display-p3 0.898 0.898 0.9176);--opaque-separator:color(display-p3 0.7765 0.7765 0.7843);--system-fill:color(display-p3 0.4706 0.4706 0.502);--secondary-system-fill:color(display-p3 0.4706 0.4706 0.502);--tertiary-system-fill:color(display-p3 0.4627 0.4627 0.502);--quaternary-system-fill:color(display-p3 0.4549 0.4549 0.502);--system-background:color(display-p3 1 1 1);--secondary-system-background:color(display-p3 0.949 0.949 0.9686);--tertiary-system-background:color(display-p3 1 1 1);--system-grouped-background:color(display-p3 0.949 0.949 0.9686);--secondary-system-grouped-background:color(display-p3 1 1 1);--tertiary-system-grouped-background:color(display-p3 0.949 0.949 0.9686)}}:root{--large-title:600 32pt/39pt sans-serif;--title-1:600 26pt/32pt sans-serif;--title-2:600 20pt/25pt sans-serif;--title-3:500 18pt/23pt sans-serif;--headline:500 15pt/20pt sans-serif;--body:300 15pt/20pt sans-serif;--callout:300 14pt/19pt sans-serif;--subhead:300 13pt/18pt sans-serif;--footnote:300 12pt/16pt sans-serif;--caption-1:300 11pt/13pt sans-serif;--caption-2:300 11pt/13pt sans-serif;--icon-case:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%2389c5e6' height='90' rx='8' stroke='%236bb7e1' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M20.21 50c0-20.7 11.9-32.79 30.8-32.79 16 0 28.21 10.33 28.7 25.32H64.19C63.4 35 58.09 30.11 51 30.11c-8.79 0-14.37 7.52-14.37 19.82s5.54 20 14.41 20c7.08 0 12.22-4.66 13.23-12.09h15.52c-.74 15.07-12.43 25-28.78 25C32 82.81 20.21 70.72 20.21 50z' fill='%23fff'/%3E%3C/svg%3E");--icon-class:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%239b98e6' height='90' rx='8' stroke='%235856d6' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='m20.21 50c0-20.7 11.9-32.79 30.8-32.79 16 0 28.21 10.33 28.7 25.32h-15.52c-.79-7.53-6.1-12.42-13.19-12.42-8.79 0-14.37 7.52-14.37 19.82s5.54 20 14.41 20c7.08 0 12.22-4.66 13.23-12.09h15.52c-.74 15.07-12.43 25-28.78 25-19.01-.03-30.8-12.12-30.8-32.84z' fill='%23fff'/%3E%3C/svg%3E");--icon-enumeration:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23eca95b' height='90' rx='8' stroke='%23e89234' stroke-miterlimit='10' stroke-width='4' width='90' x='5.17' y='5'/%3E%3Cpath d='M71.9 81.71H28.43V18.29H71.9v13H44.56v12.62h25.71v11.87H44.56V68.7H71.9z' fill='%23fff'/%3E%3C/svg%3E");--icon-extension:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23eca95b' height='90' rx='8' stroke='%23e89234' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cg fill='%23fff'%3E%3Cpath d='M54.43 81.93H20.51V18.07h33.92v12.26H32.61v13.8h20.45v11.32H32.61v14.22h21.82zM68.74 74.58h-.27l-2.78 7.35h-7.28L64 69.32l-6-12.54h8l2.74 7.3h.27l2.76-7.3h7.64l-6.14 12.54 5.89 12.61h-7.64z'/%3E%3C/g%3E%3C/svg%3E");--icon-function:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M24.25 75.66A5.47 5.47 0 0130 69.93c1.55 0 3.55.41 6.46.41 3.19 0 4.78-1.55 5.46-6.65l1.5-10.14h-9.34a6 6 0 110-12h11.1l1.09-7.27C47.82 23.39 54.28 17.7 64 17.7c6.69 0 11.74 1.77 11.74 6.64A5.47 5.47 0 0170 30.07c-1.55 0-3.55-.41-6.46-.41-3.14 0-4.73 1.51-5.46 6.65l-.78 5.27h11.44a6 6 0 11.05 12H55.6l-1.78 12.11C52.23 76.61 45.72 82.3 36 82.3c-6.7 0-11.75-1.77-11.75-6.64z' fill='%23fff'/%3E%3C/svg%3E");--icon-method:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%235a98f8' height='90' rx='8' stroke='%232974ed' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M70.61 81.71v-39.6h-.31l-15.69 39.6h-9.22l-15.65-39.6h-.35v39.6H15.2V18.29h18.63l16 41.44h.36l16-41.44H84.8v63.42z' fill='%23fff'/%3E%3C/svg%3E");--icon-property:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%2389c5e6' height='90' rx='8' stroke='%236bb7e1' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M52.31 18.29c13.62 0 22.85 8.84 22.85 22.46s-9.71 22.37-23.82 22.37H41v18.59H24.84V18.29zM41 51h7c6.85 0 10.89-3.56 10.89-10.2S54.81 30.64 48 30.64h-7z' fill='%23fff'/%3E%3C/svg%3E");--icon-protocol:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23ff6682' height='90' rx='8' stroke='%23ff2d55' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cg fill='%23fff'%3E%3Cpath d='M46.28 18.29c11.84 0 20 8.66 20 21.71s-8.44 21.71-20.6 21.71H34.87v20H22.78V18.29zM34.87 51.34H43c6.93 0 11-4 11-11.29S50 28.8 43.07 28.8h-8.2zM62 57.45h8v4.77h.16c.84-3.45 2.54-5.12 5.17-5.12a5.06 5.06 0 011.92.35V65a5.69 5.69 0 00-2.39-.51c-3.08 0-4.66 1.74-4.66 5.12v12.1H62z'/%3E%3C/g%3E%3C/svg%3E");--icon-structure:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23b57edf' height='90' rx='8' stroke='%239454c2' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M38.38 63c.74 4.53 5.62 7.16 11.82 7.16s10.37-2.81 10.37-6.68c0-3.51-2.73-5.31-10.24-6.76l-6.5-1.23C31.17 53.14 24.62 47 24.62 37.28c0-12.22 10.59-20.09 25.18-20.09 16 0 25.36 7.83 25.53 19.91h-15c-.26-4.57-4.57-7.29-10.42-7.29s-9.31 2.63-9.31 6.37c0 3.34 2.9 5.18 9.8 6.5l6.5 1.23C70.46 46.51 76.61 52 76.61 62c0 12.74-10 20.83-26.72 20.83-15.82 0-26.28-7.3-26.5-19.78z' fill='%23fff'/%3E%3C/svg%3E");--icon-typealias:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M42 81.71V31.3H24.47v-13h51.06v13H58v50.41z' fill='%23fff'/%3E%3C/svg%3E");--icon-variable:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M39.85 81.71L19.63 18.29H38l12.18 47.64h.35L62.7 18.29h17.67L60.15 81.71z' fill='%23fff'/%3E%3C/svg%3E")}body,button,input,select,textarea{-moz-font-feature-settings:"kern";-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;direction:ltr;font-synthesis:none;text-align:left}h1:first-of-type,h2:first-of-type,h3:first-of-type,h4:first-of-type,h5:first-of-type,h6:first-of-type{margin-top:0}h1 code,h2 code,h3 code,h4 code,h5 code,h6 code{font-family:inherit;font-weight:inherit}h1 img,h2 img,h3 img,h4 img,h5 img,h6 img{margin:0 .5em .2em 0;vertical-align:middle;display:inline-block}h1+*,h2+*,h3+*,h4+*,h5+*,h6+*{margin-top:.8em}img+h1{margin-top:.5em}img+h1,img+h2,img+h3,img+h4,img+h5,img+h6{margin-top:.3em}:is(h1,h2,h3,h4,h5,h6)+:is(h1,h2,h3,h4,h5,h6){margin-top:.4em}:matches(h1,h2,h3,h4,h5,h6)+:matches(h1,h2,h3,h4,h5,h6){margin-top:.4em}:is(p,ul,ol)+:is(h1,h2,h3,h4,h5,h6){margin-top:1.6em}:matches(p,ul,ol)+:matches(h1,h2,h3,h4,h5,h6){margin-top:1.6em}:is(p,ul,ol)+*{margin-top:.8em}:matches(p,ul,ol)+*{margin-top:.8em}ol,ul{margin-left:1.17647em}:matches(ul,ol) :matches(ul,ol){margin-bottom:0;margin-top:0}nav h2{color:#3c3c43;color:var(--secondary-label);font-size:1rem;font-feature-settings:"c2sc";font-variant:small-caps;font-weight:600;text-transform:uppercase}nav ol,nav ul{margin:0;list-style:none}nav li li{font-size:smaller}a:link,a:visited{text-decoration:none}a:hover{text-decoration:underline}a:active{text-decoration:none}a+a{display:inline-block}b,strong{font-weight:600}.discussion,.summary{font:300 14pt/19pt sans-serif;font:var(--callout)}article>.discussion{margin-bottom:2em}.discussion .highlight{background:transparent;border:1px solid #e5e5ea;border:1px solid var(--separator);font:300 11pt/13pt sans-serif;font:var(--caption-1);padding:1em;text-indent:0}cite,dfn,em,i{font-style:italic}:matches(h1,h2,h3) sup{font-size:.4em}sup a{color:inherit;vertical-align:inherit}sup a:hover{color:#007aff;color:var(--link);text-decoration:none}sub{line-height:1}abbr{border:0}:lang(ja),:lang(ko),:lang(th),:lang(zh){font-style:normal}:lang(ko){word-break:keep-all}form fieldset{margin:1em auto;max-width:450px;width:95%}form label{display:block;font-size:1em;font-weight:400;line-height:1.5em;margin-bottom:14px;position:relative;width:100%}input[type=email],input[type=number],input[type=password],input[type=tel],input[type=text],input[type=url],textarea{border-radius:4px;border:1px solid #e5e5ea;border:1px solid var(--separator);color:#333;font-family:inherit;font-size:100%;font-weight:400;height:34px;margin:0;padding:0 1em;position:relative;vertical-align:top;width:100%;z-index:1}input[type=email],input [type=email]:focus,input[type=number],input [type=number]:focus,input[type=password],input [type=password]:focus,input[type=tel],input [type=tel]:focus,input[type=text],input [type=text]:focus,input[type=url],input [type=url]:focus,textarea,textarea:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}input[type=email]:focus,input[type=number]:focus,input[type=password]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=url]:focus,textarea:focus{border-color:#08c;box-shadow:0 0 0 3px rgba(0,136,204,.3);outline:0;z-index:9}input[type=email]:-moz-read-only,input[type=number]:-moz-read-only,input[type=password]:-moz-read-only,input[type=tel]:-moz-read-only,input[type=text]:-moz-read-only,input[type=url]:-moz-read-only,textarea:-moz-read-only{background:none;border:none;box-shadow:none;padding-left:0}input[type=email]:read-only,input[type=number]:read-only,input[type=password]:read-only,input[type=tel]:read-only,input[type=text]:read-only,input[type=url]:read-only,textarea:read-only{background:none;border:none;box-shadow:none;padding-left:0}::-webkit-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::-moz-placeholder{color:#8e8e93;color:var(--placeholder-text)}:-ms-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::-ms-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::placeholder{color:#8e8e93;color:var(--placeholder-text)}textarea{-webkit-overflow-scrolling:touch;line-height:1.4737;min-height:134px;overflow-y:auto;resize:vertical;transform:translateZ(0)}textarea,textarea:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}select{background:transparent;border-radius:4px;border:none;cursor:pointer;font-family:inherit;font-size:1em;height:34px;margin:0;padding:0 1em;width:100%}select,select:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}select:focus{border-color:#08c;box-shadow:0 0 0 3px rgba(0,136,204,.3);outline:0;z-index:9}input[type=file]{background:#fafafa;border-radius:4px;color:#333;cursor:pointer;font-family:inherit;font-size:100%;height:34px;margin:0;padding:6px 1em;position:relative;vertical-align:top;width:100%;z-index:1}input[type=file]:focus{border-color:#08c;outline:0;box-shadow:0 0 0 3px rgba(0,136,204,.3);z-index:9}button,button:focus,input[type=file]:focus,input[type=file]:focus:focus,input[type=reset],input[type=reset]:focus,input[type=submit],input[type=submit]:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}:matches(button,input[type=reset],input[type=submit]){background-color:#e3e3e3;background:linear-gradient(#fff,#e3e3e3);border-color:#d6d6d6;color:#0070c9}:matches(button,input[type=reset],input[type=submit]):hover{background-color:#eee;background:linear-gradient(#fff,#eee);border-color:#d9d9d9}:matches(button,input[type=reset],input[type=submit]):active{background-color:#dcdcdc;background:linear-gradient(#f7f7f7,#dcdcdc);border-color:#d0d0d0}:matches(button,input[type=reset],input[type=submit]):disabled{background-color:#e3e3e3;background:linear-gradient(#fff,#e3e3e3);border-color:#d6d6d6;color:#0070c9}body{background:#f2f2f7;background:var(--system-grouped-background);color:#000;color:var(--label);font-family:ui-system,-apple-system,BlinkMacSystemFont,sans-serif;font:300 15pt/20pt sans-serif;font:var(--body)}h1{font:600 32pt/39pt sans-serif;font:var(--large-title)}h2{font:600 20pt/25pt sans-serif;font:var(--title-2)}h3{font:500 18pt/23pt sans-serif;font:var(--title-3)}h4,h5,h6{font:500 15pt/20pt sans-serif;font:var(--headline)}a{color:#007aff;color:var(--link)}label{font:300 14pt/19pt sans-serif;font:var(--callout)}input,label{display:block}input{margin-bottom:1em}hr{border:none;border-top:1px solid #e5e5ea;border-top:1px solid var(--separator);margin:1em 0}table{width:100%;font:300 11pt/13pt sans-serif;font:var(--caption-1);caption-side:bottom;margin-bottom:2em}td,th{padding:0 1em}th{font-weight:600;text-align:left}thead th{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator)}tr:last-of-type td,tr:last-of-type th{border-bottom:none}td,th{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);color:#3c3c43;color:var(--secondary-label)}caption{color:#48484a;color:var(--tertiary-label);font:300 11pt/13pt sans-serif;font:var(--caption-2);margin-top:2em;text-align:left}.graph text,code{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-weight:300}.graph>polygon{display:none}.graph text{fill:currentColor!important}.graph ellipse,.graph path,.graph polygon,.graph rect{stroke:currentColor!important}body{width:90vw;max-width:1280px;margin:1em auto}body>header{font:600 26pt/32pt sans-serif;font:var(--title-1);padding:.5em 0}body>header a{color:#000;color:var(--label)}body>header span{font-weight:400}body>header sup{text-transform:uppercase;font-size:small;font-weight:300;letter-spacing:.1ch}body>footer,body>header sup{color:#3c3c43;color:var(--secondary-label)}body>footer{clear:both;padding:1em 0;font:300 11pt/13pt sans-serif;font:var(--caption-1)}@media screen and (max-width:768px){body{width:96vw;max-width:100%}body>header{font:500 18pt/23pt sans-serif;font:var(--title-3);text-align:left;padding:1em 0}body>nav{display:none}body>main{padding:0 1em}}@media screen and (max-width:768px){#relationships figure{display:none}section>[role=article][class] pre{margin-left:-2.5em}section>[role=article][class] div{margin-left:-2em}}main,nav{overflow-x:scroll}main{background:#fff;background:var(--system-background);border-radius:8px;padding:0 2em}main section{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);margin-bottom:2em;padding-bottom:1em}main section:last-of-type{border-bottom:none;margin-bottom:0}nav{float:right;margin-left:1em;max-height:100vh;overflow:scroll;padding:0 1em 3em;position:-webkit-sticky;position:sticky;top:1em;width:20vw}nav a{color:#3c3c43;color:var(--secondary-label)}nav ul a{color:#48484a;color:var(--tertiary-label)}nav ol,nav ul{padding:0}nav ul{font:300 14pt/19pt sans-serif;font:var(--callout);margin-bottom:1em}nav ol>li>a{display:block;font-size:smaller;font:500 15pt/20pt sans-serif;font:var(--headline);margin:.5em 0}nav li{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}blockquote{--link:var(--secondary-label);border-left:4px solid #e5e5ea;border-left:4px solid var(--separator);color:#3c3c43;color:var(--secondary-label);font-size:smaller;margin-left:0;padding-left:2em}blockquote a{text-decoration:underline}article{padding:2em 0 1em}article>.summary{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);margin-bottom:2em;padding-bottom:1em}article>.summary:last-child{border-bottom:none}.parameters th{text-align:right}.parameters td{color:#3c3c43;color:var(--secondary-label)}.parameters th+td{text-align:center}dl{padding-top:1em}dt{font:500 15pt/20pt sans-serif;font:var(--headline)}dd{margin-left:2em;margin-bottom:1em}dd p{margin-top:0}.highlight{background:#f2f2f7;background:var(--secondary-system-background);border-radius:8px;font-size:smaller;margin-bottom:2em;overflow-x:scroll;padding:1em 1em 1em 3em;text-indent:-2em;white-space:pre-line}.highlight .p{white-space:nowrap}.highlight .placeholder{color:#000;color:var(--label)}.highlight a{text-decoration:underline;color:#8e8e93;color:var(--placeholder-text)}.highlight .attribute,.highlight .keyword,.highlight .literal{color:#af52de;color:var(--system-purple)}.highlight .number{color:#007aff;color:var(--system-blue)}.highlight .declaration{color:#5ac8fa;color:var(--system-teal)}.highlight .type{color:#5856d6;color:var(--system-indigo)}.highlight .directive{color:#ff9500;color:var(--system-orange)}.highlight .comment{color:#8e8e93;color:var(--system-gray)}main summary:hover{text-decoration:underline}figure{margin:2em 0;padding:1em 0}figure svg{max-width:100%;height:auto!important;margin:0 auto;display:block}h1 small{font-size:.5em;line-height:1.5;display:block;font-weight:400;color:#636366;color:var(--quaternary-label)}dd code,li code,p code{font-size:smaller;color:#3c3c43;color:var(--secondary-label)}a code{text-decoration:underline}dl dt[class],nav li[class],section>[role=article][class]{background-image:var(--background-image);background-size:1em;background-repeat:no-repeat;background-position:left .25em;padding-left:3em}dl dt[class]{background-position-y:.125em}section>[role=article]{margin-bottom:1em;padding-bottom:1em;border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);padding-left:2em!important}section>[role=article]:last-of-type{margin-bottom:0;padding-bottom:0;border-bottom:none}dl dt[class],nav li[class]{list-style:none;text-indent:-1em;margin-bottom:.5em}nav li[class]{padding-left:2.5em}.case,.enumeration_case{--background-image:var(--icon-case);--link:var(--system-teal)}.class{--background-image:var(--icon-class);--link:var(--system-indigo)}.enumeration{--background-image:var(--icon-enumeration)}.enumeration,.extension{--link:var(--system-orange)}.extension{--background-image:var(--icon-extension)}.function{--background-image:var(--icon-function);--link:var(--system-green)}.initializer,.method{--background-image:var(--icon-method);--link:var(--system-blue)}.property{--background-image:var(--icon-property);--link:var(--system-teal)}.protocol{--background-image:var(--icon-protocol);--link:var(--system-pink)}.structure{--background-image:var(--icon-structure);--link:var(--system-purple)}.typealias{--background-image:var(--icon-typealias)}.typealias,.variable{--link:var(--system-green)}.variable{--background-image:var(--icon-variable)}.unknown{--link:var(--quaternary-label);color:#007aff;color:var(--link)}
\ No newline at end of file
diff --git a/Documentation/index.html b/Documentation/index.html
index ece4a00..9b2d3ac 100755
--- a/Documentation/index.html
+++ b/Documentation/index.html
@@ -4,1178 +4,7 @@
MultipeerKit - MultipeerKit
-
+
@@ -1207,7 +36,7 @@ On This Page
Classes
-
-
+
MultipeerDataSource
@@ -1215,7 +44,7 @@ Classes
-
-
+
MultipeerTransceiver
@@ -1229,7 +58,7 @@ Classes
Structures
-
-
+
Peer
@@ -1238,7 +67,7 @@ Structures
-
-
+
MultipeerConfiguration
@@ -1247,7 +76,7 @@ Structures
-
-
+
MultipeerConfiguration.Security
@@ -1261,7 +90,7 @@ Structures
Enumerations
-
-
+
MultipeerConfiguration.Invitation
@@ -1278,7 +107,7 @@ Enumerations
diff --git a/README.md b/README.md
index 55a2b53..1ea415f 100644
--- a/README.md
+++ b/README.md
@@ -22,8 +22,8 @@ let transceiver = MultipeerTransceiver()
transceiver.resume()
// Configure message receivers
-transceiver.receive(SomeCodableThing.self) { payload in
- print("Got my thing! \(payload)")
+transceiver.receive(SomeCodableThing.self) { payload, sender in
+print("Got my thing from \(sender.name)! \(payload)")
}
// Broadcast message to peers
@@ -45,4 +45,4 @@ let package = Package(
],
...
)
-```
\ No newline at end of file
+```
diff --git a/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift b/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift
index f6e257b..7e58550 100644
--- a/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift
+++ b/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift
@@ -1,8 +1,14 @@
import Foundation
+import MultipeerConnectivity.MCPeerID
final class MockMultipeerConnection: MultipeerProtocol {
- var didReceiveData: ((Data, PeerName) -> Void)?
+ let localPeer: Peer = {
+ let underlyingPeer = MCPeerID(displayName: "MockPeer")
+ return try! Peer(peer: underlyingPeer, discoveryInfo: nil)
+ }()
+
+ var didReceiveData: ((Data, Peer) -> Void)?
var didFindPeer: ((Peer) -> Void)?
var didLosePeer: ((Peer) -> Void)?
var didConnectToPeer: ((Peer) -> Void)?
@@ -19,7 +25,7 @@ final class MockMultipeerConnection: MultipeerProtocol {
}
func broadcast(_ data: Data) throws {
- didReceiveData?(data, "MockPeer")
+ didReceiveData?(data, localPeer)
}
func send(_ data: Data, to peers: [Peer]) throws {
@@ -31,7 +37,7 @@ final class MockMultipeerConnection: MultipeerProtocol {
}
func getLocalPeerId() -> String? {
- return "MockId"
+ return localPeer.id
}
}
diff --git a/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift b/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift
index a535eb5..890802f 100644
--- a/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift
+++ b/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift
@@ -27,6 +27,8 @@
import Foundation
struct MultipeerMessage: Codable {
+ static let senderUserInfoKey = CodingUserInfoKey(rawValue: "sender")!
+
let type: String
let payload: Any?
@@ -40,17 +42,17 @@ struct MultipeerMessage: Codable {
case payload
}
- private typealias MessageDecoder = (KeyedDecodingContainer) throws -> Any
+ private typealias MessageDecoder = (KeyedDecodingContainer, Peer) throws -> Any
private typealias MessageEncoder = (Any, inout KeyedEncodingContainer) throws -> Void
private static var decoders: [String: MessageDecoder] = [:]
private static var encoders: [String: MessageEncoder] = [:]
- static func register(_ type: T.Type, for typeName: String, closure: @escaping (T) -> Void) {
- decoders[typeName] = { container in
+ static func register(_ type: T.Type, for typeName: String, closure: @escaping (T, Peer) -> Void) {
+ decoders[typeName] = { container, peer in
let payload = try container.decode(T.self, forKey: .payload)
- DispatchQueue.main.async { closure(payload) }
+ DispatchQueue.main.async { closure(payload, peer) }
return payload
}
@@ -67,9 +69,11 @@ struct MultipeerMessage: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
type = try container.decode(String.self, forKey: .type)
+
+ let sender = decoder.userInfo[MultipeerMessage.senderUserInfoKey]! as! Peer
if let decode = Self.decoders[type] {
- payload = try decode(container)
+ payload = try decode(container, sender)
} else {
payload = nil
}
diff --git a/Sources/MultipeerKit/Internal API/MultipeerConnection.swift b/Sources/MultipeerKit/Internal API/MultipeerConnection.swift
index 0ed0bfe..e8420a0 100644
--- a/Sources/MultipeerKit/Internal API/MultipeerConnection.swift
+++ b/Sources/MultipeerKit/Internal API/MultipeerConnection.swift
@@ -27,7 +27,7 @@ final class MultipeerConnection: NSObject, MultipeerProtocol {
self.me = MCPeerID.fetchOrCreate(with: configuration)
}
- var didReceiveData: ((Data, PeerName) -> Void)?
+ var didReceiveData: ((Data, Peer) -> Void)?
var didFindPeer: ((Peer) -> Void)?
var didLosePeer: ((Peer) -> Void)?
var didConnectToPeer: ((Peer) -> Void)?
@@ -145,7 +145,11 @@ extension MultipeerConnection: MCSessionDelegate {
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
os_log("%{public}@", log: log, type: .debug, #function)
- didReceiveData?(data, peerID.displayName)
+ if let peer = try? Peer(peer: peerID, discoveryInfo: nil) {
+ didReceiveData?(data, peer)
+ } else {
+ os_log("Received data, but cannot create peer for %s", log: log, type: .error, #function, peerID.displayName)
+ }
}
func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {
diff --git a/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift b/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift
index cab54b9..97f63b5 100644
--- a/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift
+++ b/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift
@@ -4,7 +4,7 @@ typealias PeerName = String
protocol MultipeerProtocol: AnyObject {
- var didReceiveData: ((Data, PeerName) -> Void)? { get set }
+ var didReceiveData: ((Data, Peer) -> Void)? { get set }
var didFindPeer: ((Peer) -> Void)? { get set }
var didLosePeer: ((Peer) -> Void)? { get set }
var didConnectToPeer: ((Peer) -> Void)? { get set }
diff --git a/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift b/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift
index 2b0828d..0ab3447 100644
--- a/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift
+++ b/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift
@@ -74,12 +74,13 @@ public final class MultipeerTransceiver {
/// - type: The `Codable` type to receive.
/// - closure: The closure that will be called whenever a payload of the specified type is received.
/// - payload: The payload decoded from the remote message.
+ /// - sender: The remote peer who sent the message.
///
/// MultipeerKit communicates data between peers as JSON-encoded payloads which originate with
/// `Codable` entities. You register a closure to handle each specific type of entity,
/// and this closure is automatically called by the framework when a remote peer sends
/// a message containing an entity that decodes to the specified type.
- public func receive(_ type: T.Type, using closure: @escaping (_ payload: T) -> Void) {
+ public func receive(_ type: T.Type, using closure: @escaping (_ payload: T, _ sender: Peer) -> Void) {
MultipeerMessage.register(type, for: String(describing: type), closure: closure)
}
@@ -127,11 +128,13 @@ public final class MultipeerTransceiver {
}
}
- private func handleDataReceived(_ data: Data, from peer: PeerName) {
+ private func handleDataReceived(_ data: Data, from peer: Peer) {
os_log("%{public}@", log: log, type: .debug, #function)
do {
- let message = try JSONDecoder().decode(MultipeerMessage.self, from: data)
+ let decoder = JSONDecoder()
+ decoder.userInfo[MultipeerMessage.senderUserInfoKey] = peer
+ let message = try decoder.decode(MultipeerMessage.self, from: data)
os_log("Received message %@", log: self.log, type: .debug, String(describing: message))
} catch {
diff --git a/Tests/MultipeerKitTests/MultipeerKitTests.swift b/Tests/MultipeerKitTests/MultipeerKitTests.swift
index 6e993a8..4cdbc8d 100644
--- a/Tests/MultipeerKitTests/MultipeerKitTests.swift
+++ b/Tests/MultipeerKitTests/MultipeerKitTests.swift
@@ -36,8 +36,9 @@ final class MultipeerKitTests: XCTestCase {
let expect = XCTestExpectation(description: "Receive payload")
- mock.receive(TestPayload.self) { p in
- XCTAssertEqual(p, tsPayload)
+ mock.receive(TestPayload.self) { payload, sender in
+ XCTAssertEqual(payload, tsPayload)
+ XCTAssertEqual(sender.id, mock.localPeerId!)
expect.fulfill()
}
diff --git a/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift b/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift
index 9f0143c..9de1890 100644
--- a/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift
+++ b/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift
@@ -24,10 +24,10 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
let t = MultipeerTransceiver(configuration: config)
- t.receive(ExamplePayload.self) { [weak self] payload in
+ t.receive(ExamplePayload.self) { [weak self] payload, peer in
print("Got payload: \(payload)")
- self?.notify(with: payload)
+ self?.notify(with: payload, peer: peer)
}
return t
@@ -37,9 +37,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
MultipeerDataSource(transceiver: transceiver)
}()
- private func notify(with payload: ExamplePayload) {
+ private func notify(with payload: ExamplePayload, peer: Peer) {
let content = UNMutableNotificationContent()
- content.body = payload.message
+ content.body = "\"\(payload.message)\" from \(peer.name)"
let request = UNNotificationRequest(identifier: payload.message, content: content, trigger: nil)
UNUserNotificationCenter.current().add(request) { _ in
@available(tvOS 13.0, *) @available(OSX 10.15, *) @available(iOS 13.0, *) public final class MultipeerDataSource: ObservableObject
Relationships
-Relationships
Relationships
-Conforms To
Hashable
Identifiable
Initializers
+ +
+ init(peer:discoveryInfo:)
+
+ init(peer: MCPeerID, discoveryInfo: [String: String]?) throws
+Properties
-
+ underlyingPeer
+
+ let underlyingPeer: MCPeerID
+
id
@@ -1284,7 +129,7 @@
name
@@ -1294,7 +139,7 @@
discoveryInfo
@@ -1304,7 +149,7 @@
isConnected
@@ -1323,7 +168,7 @@
diff --git a/Documentation/all.css b/Documentation/all.css
new file mode 100755
index 0000000..4e9b4a7
--- /dev/null
+++ b/Documentation/all.css
@@ -0,0 +1 @@
+:root{--system-red:#ff3b30;--system-orange:#ff9500;--system-yellow:#fc0;--system-green:#34c759;--system-teal:#5ac8fa;--system-blue:#007aff;--system-indigo:#5856d6;--system-purple:#af52de;--system-pink:#ff2d55;--system-gray:#8e8e93;--system-gray2:#aeaeb2;--system-gray3:#c7c7cc;--system-gray4:#d1d1d6;--system-gray5:#e5e5ea;--system-gray6:#f2f2f7;--label:#000;--secondary-label:#3c3c43;--tertiary-label:#48484a;--quaternary-label:#636366;--placeholder-text:#8e8e93;--link:#007aff;--separator:#e5e5ea;--opaque-separator:#c6c6c8;--system-fill:#787880;--secondary-system-fill:#787880;--tertiary-system-fill:#767680;--quaternary-system-fill:#747480;--system-background:#fff;--secondary-system-background:#f2f2f7;--tertiary-system-background:#fff;--system-grouped-background:#f2f2f7;--secondary-system-grouped-background:#fff;--tertiary-system-grouped-background:#f2f2f7}@supports (color:color(display-p3 1 1 1)){:root{--system-red:color(display-p3 1 0.2314 0.1882);--system-orange:color(display-p3 1 0.5843 0);--system-yellow:color(display-p3 1 0.8 0);--system-green:color(display-p3 0.2039 0.7804 0.349);--system-teal:color(display-p3 0.3529 0.7843 0.9804);--system-blue:color(display-p3 0 0.4784 1);--system-indigo:color(display-p3 0.3451 0.3373 0.8392);--system-purple:color(display-p3 0.6863 0.3216 0.8706);--system-pink:color(display-p3 1 0.1765 0.3333);--system-gray:color(display-p3 0.5569 0.5569 0.5765);--system-gray2:color(display-p3 0.6824 0.6824 0.698);--system-gray3:color(display-p3 0.7804 0.7804 0.8);--system-gray4:color(display-p3 0.8196 0.8196 0.8392);--system-gray5:color(display-p3 0.898 0.898 0.9176);--system-gray6:color(display-p3 0.949 0.949 0.9686);--label:color(display-p3 0 0 0);--secondary-label:color(display-p3 0.2353 0.2353 0.2627);--tertiary-label:color(display-p3 0.2823 0.2823 0.2901);--quaternary-label:color(display-p3 0.4627 0.4627 0.5019);--placeholder-text:color(display-p3 0.5568 0.5568 0.5764);--link:color(display-p3 0 0.4784 1);--separator:color(display-p3 0.898 0.898 0.9176);--opaque-separator:color(display-p3 0.7765 0.7765 0.7843);--system-fill:color(display-p3 0.4706 0.4706 0.502);--secondary-system-fill:color(display-p3 0.4706 0.4706 0.502);--tertiary-system-fill:color(display-p3 0.4627 0.4627 0.502);--quaternary-system-fill:color(display-p3 0.4549 0.4549 0.502);--system-background:color(display-p3 1 1 1);--secondary-system-background:color(display-p3 0.949 0.949 0.9686);--tertiary-system-background:color(display-p3 1 1 1);--system-grouped-background:color(display-p3 0.949 0.949 0.9686);--secondary-system-grouped-background:color(display-p3 1 1 1);--tertiary-system-grouped-background:color(display-p3 0.949 0.949 0.9686)}}:root{--large-title:600 32pt/39pt sans-serif;--title-1:600 26pt/32pt sans-serif;--title-2:600 20pt/25pt sans-serif;--title-3:500 18pt/23pt sans-serif;--headline:500 15pt/20pt sans-serif;--body:300 15pt/20pt sans-serif;--callout:300 14pt/19pt sans-serif;--subhead:300 13pt/18pt sans-serif;--footnote:300 12pt/16pt sans-serif;--caption-1:300 11pt/13pt sans-serif;--caption-2:300 11pt/13pt sans-serif;--icon-case:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%2389c5e6' height='90' rx='8' stroke='%236bb7e1' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M20.21 50c0-20.7 11.9-32.79 30.8-32.79 16 0 28.21 10.33 28.7 25.32H64.19C63.4 35 58.09 30.11 51 30.11c-8.79 0-14.37 7.52-14.37 19.82s5.54 20 14.41 20c7.08 0 12.22-4.66 13.23-12.09h15.52c-.74 15.07-12.43 25-28.78 25C32 82.81 20.21 70.72 20.21 50z' fill='%23fff'/%3E%3C/svg%3E");--icon-class:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%239b98e6' height='90' rx='8' stroke='%235856d6' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='m20.21 50c0-20.7 11.9-32.79 30.8-32.79 16 0 28.21 10.33 28.7 25.32h-15.52c-.79-7.53-6.1-12.42-13.19-12.42-8.79 0-14.37 7.52-14.37 19.82s5.54 20 14.41 20c7.08 0 12.22-4.66 13.23-12.09h15.52c-.74 15.07-12.43 25-28.78 25-19.01-.03-30.8-12.12-30.8-32.84z' fill='%23fff'/%3E%3C/svg%3E");--icon-enumeration:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23eca95b' height='90' rx='8' stroke='%23e89234' stroke-miterlimit='10' stroke-width='4' width='90' x='5.17' y='5'/%3E%3Cpath d='M71.9 81.71H28.43V18.29H71.9v13H44.56v12.62h25.71v11.87H44.56V68.7H71.9z' fill='%23fff'/%3E%3C/svg%3E");--icon-extension:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23eca95b' height='90' rx='8' stroke='%23e89234' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cg fill='%23fff'%3E%3Cpath d='M54.43 81.93H20.51V18.07h33.92v12.26H32.61v13.8h20.45v11.32H32.61v14.22h21.82zM68.74 74.58h-.27l-2.78 7.35h-7.28L64 69.32l-6-12.54h8l2.74 7.3h.27l2.76-7.3h7.64l-6.14 12.54 5.89 12.61h-7.64z'/%3E%3C/g%3E%3C/svg%3E");--icon-function:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M24.25 75.66A5.47 5.47 0 0130 69.93c1.55 0 3.55.41 6.46.41 3.19 0 4.78-1.55 5.46-6.65l1.5-10.14h-9.34a6 6 0 110-12h11.1l1.09-7.27C47.82 23.39 54.28 17.7 64 17.7c6.69 0 11.74 1.77 11.74 6.64A5.47 5.47 0 0170 30.07c-1.55 0-3.55-.41-6.46-.41-3.14 0-4.73 1.51-5.46 6.65l-.78 5.27h11.44a6 6 0 11.05 12H55.6l-1.78 12.11C52.23 76.61 45.72 82.3 36 82.3c-6.7 0-11.75-1.77-11.75-6.64z' fill='%23fff'/%3E%3C/svg%3E");--icon-method:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%235a98f8' height='90' rx='8' stroke='%232974ed' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M70.61 81.71v-39.6h-.31l-15.69 39.6h-9.22l-15.65-39.6h-.35v39.6H15.2V18.29h18.63l16 41.44h.36l16-41.44H84.8v63.42z' fill='%23fff'/%3E%3C/svg%3E");--icon-property:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%2389c5e6' height='90' rx='8' stroke='%236bb7e1' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M52.31 18.29c13.62 0 22.85 8.84 22.85 22.46s-9.71 22.37-23.82 22.37H41v18.59H24.84V18.29zM41 51h7c6.85 0 10.89-3.56 10.89-10.2S54.81 30.64 48 30.64h-7z' fill='%23fff'/%3E%3C/svg%3E");--icon-protocol:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23ff6682' height='90' rx='8' stroke='%23ff2d55' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cg fill='%23fff'%3E%3Cpath d='M46.28 18.29c11.84 0 20 8.66 20 21.71s-8.44 21.71-20.6 21.71H34.87v20H22.78V18.29zM34.87 51.34H43c6.93 0 11-4 11-11.29S50 28.8 43.07 28.8h-8.2zM62 57.45h8v4.77h.16c.84-3.45 2.54-5.12 5.17-5.12a5.06 5.06 0 011.92.35V65a5.69 5.69 0 00-2.39-.51c-3.08 0-4.66 1.74-4.66 5.12v12.1H62z'/%3E%3C/g%3E%3C/svg%3E");--icon-structure:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23b57edf' height='90' rx='8' stroke='%239454c2' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M38.38 63c.74 4.53 5.62 7.16 11.82 7.16s10.37-2.81 10.37-6.68c0-3.51-2.73-5.31-10.24-6.76l-6.5-1.23C31.17 53.14 24.62 47 24.62 37.28c0-12.22 10.59-20.09 25.18-20.09 16 0 25.36 7.83 25.53 19.91h-15c-.26-4.57-4.57-7.29-10.42-7.29s-9.31 2.63-9.31 6.37c0 3.34 2.9 5.18 9.8 6.5l6.5 1.23C70.46 46.51 76.61 52 76.61 62c0 12.74-10 20.83-26.72 20.83-15.82 0-26.28-7.3-26.5-19.78z' fill='%23fff'/%3E%3C/svg%3E");--icon-typealias:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M42 81.71V31.3H24.47v-13h51.06v13H58v50.41z' fill='%23fff'/%3E%3C/svg%3E");--icon-variable:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M39.85 81.71L19.63 18.29H38l12.18 47.64h.35L62.7 18.29h17.67L60.15 81.71z' fill='%23fff'/%3E%3C/svg%3E")}body,button,input,select,textarea{-moz-font-feature-settings:"kern";-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;direction:ltr;font-synthesis:none;text-align:left}h1:first-of-type,h2:first-of-type,h3:first-of-type,h4:first-of-type,h5:first-of-type,h6:first-of-type{margin-top:0}h1 code,h2 code,h3 code,h4 code,h5 code,h6 code{font-family:inherit;font-weight:inherit}h1 img,h2 img,h3 img,h4 img,h5 img,h6 img{margin:0 .5em .2em 0;vertical-align:middle;display:inline-block}h1+*,h2+*,h3+*,h4+*,h5+*,h6+*{margin-top:.8em}img+h1{margin-top:.5em}img+h1,img+h2,img+h3,img+h4,img+h5,img+h6{margin-top:.3em}:is(h1,h2,h3,h4,h5,h6)+:is(h1,h2,h3,h4,h5,h6){margin-top:.4em}:matches(h1,h2,h3,h4,h5,h6)+:matches(h1,h2,h3,h4,h5,h6){margin-top:.4em}:is(p,ul,ol)+:is(h1,h2,h3,h4,h5,h6){margin-top:1.6em}:matches(p,ul,ol)+:matches(h1,h2,h3,h4,h5,h6){margin-top:1.6em}:is(p,ul,ol)+*{margin-top:.8em}:matches(p,ul,ol)+*{margin-top:.8em}ol,ul{margin-left:1.17647em}:matches(ul,ol) :matches(ul,ol){margin-bottom:0;margin-top:0}nav h2{color:#3c3c43;color:var(--secondary-label);font-size:1rem;font-feature-settings:"c2sc";font-variant:small-caps;font-weight:600;text-transform:uppercase}nav ol,nav ul{margin:0;list-style:none}nav li li{font-size:smaller}a:link,a:visited{text-decoration:none}a:hover{text-decoration:underline}a:active{text-decoration:none}a+a{display:inline-block}b,strong{font-weight:600}.discussion,.summary{font:300 14pt/19pt sans-serif;font:var(--callout)}article>.discussion{margin-bottom:2em}.discussion .highlight{background:transparent;border:1px solid #e5e5ea;border:1px solid var(--separator);font:300 11pt/13pt sans-serif;font:var(--caption-1);padding:1em;text-indent:0}cite,dfn,em,i{font-style:italic}:matches(h1,h2,h3) sup{font-size:.4em}sup a{color:inherit;vertical-align:inherit}sup a:hover{color:#007aff;color:var(--link);text-decoration:none}sub{line-height:1}abbr{border:0}:lang(ja),:lang(ko),:lang(th),:lang(zh){font-style:normal}:lang(ko){word-break:keep-all}form fieldset{margin:1em auto;max-width:450px;width:95%}form label{display:block;font-size:1em;font-weight:400;line-height:1.5em;margin-bottom:14px;position:relative;width:100%}input[type=email],input[type=number],input[type=password],input[type=tel],input[type=text],input[type=url],textarea{border-radius:4px;border:1px solid #e5e5ea;border:1px solid var(--separator);color:#333;font-family:inherit;font-size:100%;font-weight:400;height:34px;margin:0;padding:0 1em;position:relative;vertical-align:top;width:100%;z-index:1}input[type=email],input [type=email]:focus,input[type=number],input [type=number]:focus,input[type=password],input [type=password]:focus,input[type=tel],input [type=tel]:focus,input[type=text],input [type=text]:focus,input[type=url],input [type=url]:focus,textarea,textarea:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}input[type=email]:focus,input[type=number]:focus,input[type=password]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=url]:focus,textarea:focus{border-color:#08c;box-shadow:0 0 0 3px rgba(0,136,204,.3);outline:0;z-index:9}input[type=email]:-moz-read-only,input[type=number]:-moz-read-only,input[type=password]:-moz-read-only,input[type=tel]:-moz-read-only,input[type=text]:-moz-read-only,input[type=url]:-moz-read-only,textarea:-moz-read-only{background:none;border:none;box-shadow:none;padding-left:0}input[type=email]:read-only,input[type=number]:read-only,input[type=password]:read-only,input[type=tel]:read-only,input[type=text]:read-only,input[type=url]:read-only,textarea:read-only{background:none;border:none;box-shadow:none;padding-left:0}::-webkit-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::-moz-placeholder{color:#8e8e93;color:var(--placeholder-text)}:-ms-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::-ms-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::placeholder{color:#8e8e93;color:var(--placeholder-text)}textarea{-webkit-overflow-scrolling:touch;line-height:1.4737;min-height:134px;overflow-y:auto;resize:vertical;transform:translateZ(0)}textarea,textarea:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}select{background:transparent;border-radius:4px;border:none;cursor:pointer;font-family:inherit;font-size:1em;height:34px;margin:0;padding:0 1em;width:100%}select,select:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}select:focus{border-color:#08c;box-shadow:0 0 0 3px rgba(0,136,204,.3);outline:0;z-index:9}input[type=file]{background:#fafafa;border-radius:4px;color:#333;cursor:pointer;font-family:inherit;font-size:100%;height:34px;margin:0;padding:6px 1em;position:relative;vertical-align:top;width:100%;z-index:1}input[type=file]:focus{border-color:#08c;outline:0;box-shadow:0 0 0 3px rgba(0,136,204,.3);z-index:9}button,button:focus,input[type=file]:focus,input[type=file]:focus:focus,input[type=reset],input[type=reset]:focus,input[type=submit],input[type=submit]:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}:matches(button,input[type=reset],input[type=submit]){background-color:#e3e3e3;background:linear-gradient(#fff,#e3e3e3);border-color:#d6d6d6;color:#0070c9}:matches(button,input[type=reset],input[type=submit]):hover{background-color:#eee;background:linear-gradient(#fff,#eee);border-color:#d9d9d9}:matches(button,input[type=reset],input[type=submit]):active{background-color:#dcdcdc;background:linear-gradient(#f7f7f7,#dcdcdc);border-color:#d0d0d0}:matches(button,input[type=reset],input[type=submit]):disabled{background-color:#e3e3e3;background:linear-gradient(#fff,#e3e3e3);border-color:#d6d6d6;color:#0070c9}body{background:#f2f2f7;background:var(--system-grouped-background);color:#000;color:var(--label);font-family:ui-system,-apple-system,BlinkMacSystemFont,sans-serif;font:300 15pt/20pt sans-serif;font:var(--body)}h1{font:600 32pt/39pt sans-serif;font:var(--large-title)}h2{font:600 20pt/25pt sans-serif;font:var(--title-2)}h3{font:500 18pt/23pt sans-serif;font:var(--title-3)}h4,h5,h6{font:500 15pt/20pt sans-serif;font:var(--headline)}a{color:#007aff;color:var(--link)}label{font:300 14pt/19pt sans-serif;font:var(--callout)}input,label{display:block}input{margin-bottom:1em}hr{border:none;border-top:1px solid #e5e5ea;border-top:1px solid var(--separator);margin:1em 0}table{width:100%;font:300 11pt/13pt sans-serif;font:var(--caption-1);caption-side:bottom;margin-bottom:2em}td,th{padding:0 1em}th{font-weight:600;text-align:left}thead th{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator)}tr:last-of-type td,tr:last-of-type th{border-bottom:none}td,th{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);color:#3c3c43;color:var(--secondary-label)}caption{color:#48484a;color:var(--tertiary-label);font:300 11pt/13pt sans-serif;font:var(--caption-2);margin-top:2em;text-align:left}.graph text,code{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-weight:300}.graph>polygon{display:none}.graph text{fill:currentColor!important}.graph ellipse,.graph path,.graph polygon,.graph rect{stroke:currentColor!important}body{width:90vw;max-width:1280px;margin:1em auto}body>header{font:600 26pt/32pt sans-serif;font:var(--title-1);padding:.5em 0}body>header a{color:#000;color:var(--label)}body>header span{font-weight:400}body>header sup{text-transform:uppercase;font-size:small;font-weight:300;letter-spacing:.1ch}body>footer,body>header sup{color:#3c3c43;color:var(--secondary-label)}body>footer{clear:both;padding:1em 0;font:300 11pt/13pt sans-serif;font:var(--caption-1)}@media screen and (max-width:768px){body{width:96vw;max-width:100%}body>header{font:500 18pt/23pt sans-serif;font:var(--title-3);text-align:left;padding:1em 0}body>nav{display:none}body>main{padding:0 1em}}@media screen and (max-width:768px){#relationships figure{display:none}section>[role=article][class] pre{margin-left:-2.5em}section>[role=article][class] div{margin-left:-2em}}main,nav{overflow-x:scroll}main{background:#fff;background:var(--system-background);border-radius:8px;padding:0 2em}main section{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);margin-bottom:2em;padding-bottom:1em}main section:last-of-type{border-bottom:none;margin-bottom:0}nav{float:right;margin-left:1em;max-height:100vh;overflow:scroll;padding:0 1em 3em;position:-webkit-sticky;position:sticky;top:1em;width:20vw}nav a{color:#3c3c43;color:var(--secondary-label)}nav ul a{color:#48484a;color:var(--tertiary-label)}nav ol,nav ul{padding:0}nav ul{font:300 14pt/19pt sans-serif;font:var(--callout);margin-bottom:1em}nav ol>li>a{display:block;font-size:smaller;font:500 15pt/20pt sans-serif;font:var(--headline);margin:.5em 0}nav li{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}blockquote{--link:var(--secondary-label);border-left:4px solid #e5e5ea;border-left:4px solid var(--separator);color:#3c3c43;color:var(--secondary-label);font-size:smaller;margin-left:0;padding-left:2em}blockquote a{text-decoration:underline}article{padding:2em 0 1em}article>.summary{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);margin-bottom:2em;padding-bottom:1em}article>.summary:last-child{border-bottom:none}.parameters th{text-align:right}.parameters td{color:#3c3c43;color:var(--secondary-label)}.parameters th+td{text-align:center}dl{padding-top:1em}dt{font:500 15pt/20pt sans-serif;font:var(--headline)}dd{margin-left:2em;margin-bottom:1em}dd p{margin-top:0}.highlight{background:#f2f2f7;background:var(--secondary-system-background);border-radius:8px;font-size:smaller;margin-bottom:2em;overflow-x:scroll;padding:1em 1em 1em 3em;text-indent:-2em;white-space:pre-line}.highlight .p{white-space:nowrap}.highlight .placeholder{color:#000;color:var(--label)}.highlight a{text-decoration:underline;color:#8e8e93;color:var(--placeholder-text)}.highlight .attribute,.highlight .keyword,.highlight .literal{color:#af52de;color:var(--system-purple)}.highlight .number{color:#007aff;color:var(--system-blue)}.highlight .declaration{color:#5ac8fa;color:var(--system-teal)}.highlight .type{color:#5856d6;color:var(--system-indigo)}.highlight .directive{color:#ff9500;color:var(--system-orange)}.highlight .comment{color:#8e8e93;color:var(--system-gray)}main summary:hover{text-decoration:underline}figure{margin:2em 0;padding:1em 0}figure svg{max-width:100%;height:auto!important;margin:0 auto;display:block}h1 small{font-size:.5em;line-height:1.5;display:block;font-weight:400;color:#636366;color:var(--quaternary-label)}dd code,li code,p code{font-size:smaller;color:#3c3c43;color:var(--secondary-label)}a code{text-decoration:underline}dl dt[class],nav li[class],section>[role=article][class]{background-image:var(--background-image);background-size:1em;background-repeat:no-repeat;background-position:left .25em;padding-left:3em}dl dt[class]{background-position-y:.125em}section>[role=article]{margin-bottom:1em;padding-bottom:1em;border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);padding-left:2em!important}section>[role=article]:last-of-type{margin-bottom:0;padding-bottom:0;border-bottom:none}dl dt[class],nav li[class]{list-style:none;text-indent:-1em;margin-bottom:.5em}nav li[class]{padding-left:2.5em}.case,.enumeration_case{--background-image:var(--icon-case);--link:var(--system-teal)}.class{--background-image:var(--icon-class);--link:var(--system-indigo)}.enumeration{--background-image:var(--icon-enumeration)}.enumeration,.extension{--link:var(--system-orange)}.extension{--background-image:var(--icon-extension)}.function{--background-image:var(--icon-function);--link:var(--system-green)}.initializer,.method{--background-image:var(--icon-method);--link:var(--system-blue)}.property{--background-image:var(--icon-property);--link:var(--system-teal)}.protocol{--background-image:var(--icon-protocol);--link:var(--system-pink)}.structure{--background-image:var(--icon-structure);--link:var(--system-purple)}.typealias{--background-image:var(--icon-typealias)}.typealias,.variable{--link:var(--system-green)}.variable{--background-image:var(--icon-variable)}.unknown{--link:var(--quaternary-label);color:#007aff;color:var(--link)}
\ No newline at end of file
diff --git a/Documentation/index.html b/Documentation/index.html
index ece4a00..9b2d3ac 100755
--- a/Documentation/index.html
+++ b/Documentation/index.html
@@ -4,1178 +4,7 @@
MultipeerKit - MultipeerKit
-
+
@@ -1207,7 +36,7 @@ On This Page
Classes
-
-
+
MultipeerDataSource
@@ -1215,7 +44,7 @@ Classes
-
-
+
MultipeerTransceiver
@@ -1229,7 +58,7 @@ Classes
Structures
-
-
+
Peer
@@ -1238,7 +67,7 @@ Structures
-
-
+
MultipeerConfiguration
@@ -1247,7 +76,7 @@ Structures
-
-
+
MultipeerConfiguration.Security
@@ -1261,7 +90,7 @@ Structures
Enumerations
-
-
+
MultipeerConfiguration.Invitation
@@ -1278,7 +107,7 @@ Enumerations
diff --git a/README.md b/README.md
index 55a2b53..1ea415f 100644
--- a/README.md
+++ b/README.md
@@ -22,8 +22,8 @@ let transceiver = MultipeerTransceiver()
transceiver.resume()
// Configure message receivers
-transceiver.receive(SomeCodableThing.self) { payload in
- print("Got my thing! \(payload)")
+transceiver.receive(SomeCodableThing.self) { payload, sender in
+print("Got my thing from \(sender.name)! \(payload)")
}
// Broadcast message to peers
@@ -45,4 +45,4 @@ let package = Package(
],
...
)
-```
\ No newline at end of file
+```
diff --git a/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift b/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift
index f6e257b..7e58550 100644
--- a/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift
+++ b/Sources/MultipeerKit/Internal API/MockMultipeerConnection.swift
@@ -1,8 +1,14 @@
import Foundation
+import MultipeerConnectivity.MCPeerID
final class MockMultipeerConnection: MultipeerProtocol {
- var didReceiveData: ((Data, PeerName) -> Void)?
+ let localPeer: Peer = {
+ let underlyingPeer = MCPeerID(displayName: "MockPeer")
+ return try! Peer(peer: underlyingPeer, discoveryInfo: nil)
+ }()
+
+ var didReceiveData: ((Data, Peer) -> Void)?
var didFindPeer: ((Peer) -> Void)?
var didLosePeer: ((Peer) -> Void)?
var didConnectToPeer: ((Peer) -> Void)?
@@ -19,7 +25,7 @@ final class MockMultipeerConnection: MultipeerProtocol {
}
func broadcast(_ data: Data) throws {
- didReceiveData?(data, "MockPeer")
+ didReceiveData?(data, localPeer)
}
func send(_ data: Data, to peers: [Peer]) throws {
@@ -31,7 +37,7 @@ final class MockMultipeerConnection: MultipeerProtocol {
}
func getLocalPeerId() -> String? {
- return "MockId"
+ return localPeer.id
}
}
diff --git a/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift b/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift
index a535eb5..890802f 100644
--- a/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift
+++ b/Sources/MultipeerKit/Internal API/Models/MultipeerMessage.swift
@@ -27,6 +27,8 @@
import Foundation
struct MultipeerMessage: Codable {
+ static let senderUserInfoKey = CodingUserInfoKey(rawValue: "sender")!
+
let type: String
let payload: Any?
@@ -40,17 +42,17 @@ struct MultipeerMessage: Codable {
case payload
}
- private typealias MessageDecoder = (KeyedDecodingContainer) throws -> Any
+ private typealias MessageDecoder = (KeyedDecodingContainer, Peer) throws -> Any
private typealias MessageEncoder = (Any, inout KeyedEncodingContainer) throws -> Void
private static var decoders: [String: MessageDecoder] = [:]
private static var encoders: [String: MessageEncoder] = [:]
- static func register(_ type: T.Type, for typeName: String, closure: @escaping (T) -> Void) {
- decoders[typeName] = { container in
+ static func register(_ type: T.Type, for typeName: String, closure: @escaping (T, Peer) -> Void) {
+ decoders[typeName] = { container, peer in
let payload = try container.decode(T.self, forKey: .payload)
- DispatchQueue.main.async { closure(payload) }
+ DispatchQueue.main.async { closure(payload, peer) }
return payload
}
@@ -67,9 +69,11 @@ struct MultipeerMessage: Codable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
type = try container.decode(String.self, forKey: .type)
+
+ let sender = decoder.userInfo[MultipeerMessage.senderUserInfoKey]! as! Peer
if let decode = Self.decoders[type] {
- payload = try decode(container)
+ payload = try decode(container, sender)
} else {
payload = nil
}
diff --git a/Sources/MultipeerKit/Internal API/MultipeerConnection.swift b/Sources/MultipeerKit/Internal API/MultipeerConnection.swift
index 0ed0bfe..e8420a0 100644
--- a/Sources/MultipeerKit/Internal API/MultipeerConnection.swift
+++ b/Sources/MultipeerKit/Internal API/MultipeerConnection.swift
@@ -27,7 +27,7 @@ final class MultipeerConnection: NSObject, MultipeerProtocol {
self.me = MCPeerID.fetchOrCreate(with: configuration)
}
- var didReceiveData: ((Data, PeerName) -> Void)?
+ var didReceiveData: ((Data, Peer) -> Void)?
var didFindPeer: ((Peer) -> Void)?
var didLosePeer: ((Peer) -> Void)?
var didConnectToPeer: ((Peer) -> Void)?
@@ -145,7 +145,11 @@ extension MultipeerConnection: MCSessionDelegate {
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
os_log("%{public}@", log: log, type: .debug, #function)
- didReceiveData?(data, peerID.displayName)
+ if let peer = try? Peer(peer: peerID, discoveryInfo: nil) {
+ didReceiveData?(data, peer)
+ } else {
+ os_log("Received data, but cannot create peer for %s", log: log, type: .error, #function, peerID.displayName)
+ }
}
func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {
diff --git a/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift b/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift
index cab54b9..97f63b5 100644
--- a/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift
+++ b/Sources/MultipeerKit/Internal API/MultipeerProtocol.swift
@@ -4,7 +4,7 @@ typealias PeerName = String
protocol MultipeerProtocol: AnyObject {
- var didReceiveData: ((Data, PeerName) -> Void)? { get set }
+ var didReceiveData: ((Data, Peer) -> Void)? { get set }
var didFindPeer: ((Peer) -> Void)? { get set }
var didLosePeer: ((Peer) -> Void)? { get set }
var didConnectToPeer: ((Peer) -> Void)? { get set }
diff --git a/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift b/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift
index 2b0828d..0ab3447 100644
--- a/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift
+++ b/Sources/MultipeerKit/Public API/MultipeerTransceiver.swift
@@ -74,12 +74,13 @@ public final class MultipeerTransceiver {
/// - type: The `Codable` type to receive.
/// - closure: The closure that will be called whenever a payload of the specified type is received.
/// - payload: The payload decoded from the remote message.
+ /// - sender: The remote peer who sent the message.
///
/// MultipeerKit communicates data between peers as JSON-encoded payloads which originate with
/// `Codable` entities. You register a closure to handle each specific type of entity,
/// and this closure is automatically called by the framework when a remote peer sends
/// a message containing an entity that decodes to the specified type.
- public func receive(_ type: T.Type, using closure: @escaping (_ payload: T) -> Void) {
+ public func receive(_ type: T.Type, using closure: @escaping (_ payload: T, _ sender: Peer) -> Void) {
MultipeerMessage.register(type, for: String(describing: type), closure: closure)
}
@@ -127,11 +128,13 @@ public final class MultipeerTransceiver {
}
}
- private func handleDataReceived(_ data: Data, from peer: PeerName) {
+ private func handleDataReceived(_ data: Data, from peer: Peer) {
os_log("%{public}@", log: log, type: .debug, #function)
do {
- let message = try JSONDecoder().decode(MultipeerMessage.self, from: data)
+ let decoder = JSONDecoder()
+ decoder.userInfo[MultipeerMessage.senderUserInfoKey] = peer
+ let message = try decoder.decode(MultipeerMessage.self, from: data)
os_log("Received message %@", log: self.log, type: .debug, String(describing: message))
} catch {
diff --git a/Tests/MultipeerKitTests/MultipeerKitTests.swift b/Tests/MultipeerKitTests/MultipeerKitTests.swift
index 6e993a8..4cdbc8d 100644
--- a/Tests/MultipeerKitTests/MultipeerKitTests.swift
+++ b/Tests/MultipeerKitTests/MultipeerKitTests.swift
@@ -36,8 +36,9 @@ final class MultipeerKitTests: XCTestCase {
let expect = XCTestExpectation(description: "Receive payload")
- mock.receive(TestPayload.self) { p in
- XCTAssertEqual(p, tsPayload)
+ mock.receive(TestPayload.self) { payload, sender in
+ XCTAssertEqual(payload, tsPayload)
+ XCTAssertEqual(sender.id, mock.localPeerId!)
expect.fulfill()
}
diff --git a/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift b/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift
index 9f0143c..9de1890 100644
--- a/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift
+++ b/example/MultipeerKitExample/MultipeerKitExample/SceneDelegate.swift
@@ -24,10 +24,10 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
let t = MultipeerTransceiver(configuration: config)
- t.receive(ExamplePayload.self) { [weak self] payload in
+ t.receive(ExamplePayload.self) { [weak self] payload, peer in
print("Got payload: \(payload)")
- self?.notify(with: payload)
+ self?.notify(with: payload, peer: peer)
}
return t
@@ -37,9 +37,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
MultipeerDataSource(transceiver: transceiver)
}()
- private func notify(with payload: ExamplePayload) {
+ private func notify(with payload: ExamplePayload, peer: Peer) {
let content = UNMutableNotificationContent()
- content.body = payload.message
+ content.body = "\"\(payload.message)\" from \(peer.name)"
let request = UNNotificationRequest(identifier: payload.message, content: content, trigger: nil)
UNUserNotificationCenter.current().add(request) { _ in
On This Page
Classes
- - + MultipeerDataSource @@ -1215,7 +44,7 @@
- - + MultipeerTransceiver @@ -1229,7 +58,7 @@
- - + Peer @@ -1238,7 +67,7 @@
- - + MultipeerConfiguration @@ -1247,7 +76,7 @@
- - + MultipeerConfiguration.Security @@ -1261,7 +90,7 @@
- - + MultipeerConfiguration.Invitation @@ -1278,7 +107,7 @@