Skip to content

Commit ad20d84

Browse files
authored
Support Bluetooth (#118)
Signed-off-by: conanoc <conanoc@gmail.com>
1 parent 101cac6 commit ad20d84

24 files changed

+461
-20
lines changed

Diff for: Package.resolved

+27
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@
2727
"version" : "3.1.0"
2828
}
2929
},
30+
{
31+
"identity" : "blueswift",
32+
"kind" : "remoteSourceControl",
33+
"location" : "https://github.com/conanoc/BlueSwift",
34+
"state" : {
35+
"revision" : "5c9cc238396061bf7f3d6056dc8fdfe060a1add3",
36+
"version" : "1.1.7"
37+
}
38+
},
3039
{
3140
"identity" : "cocoaasyncsocket",
3241
"kind" : "remoteSourceControl",
@@ -99,6 +108,15 @@
99108
"version" : "1.2.2"
100109
}
101110
},
111+
{
112+
"identity" : "swift-algorithms",
113+
"kind" : "remoteSourceControl",
114+
"location" : "https://github.com/apple/swift-algorithms",
115+
"state" : {
116+
"revision" : "f6919dfc309e7f1b56224378b11e28bab5bccc42",
117+
"version" : "1.2.0"
118+
}
119+
},
102120
{
103121
"identity" : "swift-bases",
104122
"kind" : "remoteSourceControl",
@@ -116,6 +134,15 @@
116134
"revision" : "45f3cf2844477b9d211e1d3e793d0853134fd942",
117135
"version" : "0.0.2"
118136
}
137+
},
138+
{
139+
"identity" : "swift-numerics",
140+
"kind" : "remoteSourceControl",
141+
"location" : "https://github.com/apple/swift-numerics.git",
142+
"state" : {
143+
"revision" : "0a5bc04095a675662cf24757cc0640aa2204253b",
144+
"version" : "1.0.2"
145+
}
119146
}
120147
],
121148
"version" : 2

Diff for: Package.swift

+6-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ let package = Package(
1919
.package(url: "https://github.com/keefertaylor/Base58Swift", exact: "2.1.7"),
2020
.package(url: "https://github.com/thecatalinstan/Criollo", exact: "1.1.0"),
2121
.package(url: "https://github.com/groue/Semaphore", exact: "0.0.8"),
22-
.package(url: "https://github.com/beatt83/peerdid-swift", exact: "3.0.0")
22+
.package(url: "https://github.com/beatt83/peerdid-swift", exact: "3.0.0"),
23+
.package(url: "https://github.com/apple/swift-algorithms", exact: "1.2.0"),
24+
.package(url: "https://github.com/conanoc/BlueSwift", exact: "1.1.7")
2325
],
2426
targets: [
2527
.target(
@@ -30,9 +32,11 @@ let package = Package(
3032
.product(name: "IndyVdr", package: "aries-uniffi-wrappers"),
3133
.product(name: "WebSockets", package: "concurrent-ws"),
3234
.product(name: "PeerDID", package: "peerdid-swift"),
35+
.product(name: "Algorithms", package: "swift-algorithms"),
3336
"CollectionConcurrencyKit",
3437
"Base58Swift",
35-
"Semaphore"
38+
"Semaphore",
39+
"BlueSwift"
3640
]),
3741
.testTarget(
3842
name: "AriesFrameworkTests",

Diff for: README.md

+23-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Aries Framework Swift supports most of [AIP 1.0](https://github.com/hyperledger/
1313
- ✅ ([RFC 0036](https://github.com/hyperledger/aries-rfcs/blob/master/features/0036-issue-credential/README.md)) Issue Credential Protocol
1414
- ✅ ([RFC 0037](https://github.com/hyperledger/aries-rfcs/tree/master/features/0037-present-proof/README.md)) Present Proof Protocol
1515
- Does not implement alternate begining (Prover begins with proposal)
16-
- ✅ HTTP & WebSocket Transport
16+
- ✅ HTTP, WebSocket and Bluetooth Transport
1717
- ✅ ([RFC 0434](https://github.com/hyperledger/aries-rfcs/blob/main/features/0434-outofband/README.md)) Out of Band Protocol (AIP 2.0)
1818
- ✅ ([RFC 0035](https://github.com/hyperledger/aries-rfcs/blob/main/features/0035-report-problem/README.md)) Report Problem Protocol
1919
- ✅ ([RFC 0023](https://github.com/hyperledger/aries-rfcs/tree/main/features/0023-did-exchange)) DID Exchange Protocol (AIP 2.0)
@@ -28,7 +28,7 @@ Aries Framework Swift requires iOS 15.0+ and distributed as a Swift package.
2828
Add a dependency to your `Package.swift` file:
2929
```swift
3030
dependencies: [
31-
.package(url: "https://github.com/hyperledger/aries-framework-swift", from: "2.3.0")
31+
.package(url: "https://github.com/hyperledger/aries-framework-swift", from: "2.5.0")
3232
]
3333
```
3434

@@ -140,6 +140,27 @@ Another way to handle those requests is to implement your own `MessageHandler` c
140140
agent.dispatcher.registerHandler(handler: messageHandler)
141141
```
142142

143+
## Bluetooth support
144+
145+
Aries Framework Swift supports phone to phone communication over Bluetooth.
146+
You will need to add `NSBluetoothAlwaysUsageDescription` key to the info.plist of your app to use Bluetooth.
147+
148+
### How to use
149+
150+
Verifier side:
151+
1. Call `try await agent.startBLE()` to create an endpoint over BLE. The endpoint has the form of "ble://aries/endpoint?uuid={uuid}".
152+
2. Create an oob-invitation and create a QR code with the invitation url. This invitation will use the endpoint created above even though the agent has a mediator connection. You should create an oob-invitation attaching a proof request message without handshake option. This allows the prover sends the proof directly to the verifier without preparing any endpoint.
153+
```swift
154+
let oob = try await agent!.oob.createInvitation(config: CreateOutOfBandInvitationConfig(handshake: false, messages: [message]))
155+
let invitationUrl = oob.outOfBandInvitation.toUrl(domain: "http://example.com")
156+
```
157+
3. Call `try? await agent.stopBLE()` after you finish verification.
158+
159+
Prover side:
160+
- There is nothing you need to do to communicate over BLE on prover side. The agent will recognize the `ble://` scheme and connect to the verifier's device over BLE. The connection will be closed automatically after the message is sent.
161+
162+
The sample app has sample codes that demonstrates proof exchange over Bluetooth.
163+
143164
## Sample App
144165

145166
`Sample` directory contains an iOS sample app that demonstrates how to use Aries Framework Swift. The app receives a connection invitation from a QR code or from a URL input and handles credential offers and proof requests.

Diff for: Sample/wallet-app-ios.xcodeproj/project.pbxproj

+12-6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
BB90F26828F92DA20066AE87 /* local-genesis.txn in Resources */ = {isa = PBXBuildFile; fileRef = BB90F26628F92DA10066AE87 /* local-genesis.txn */; };
2121
BBB509D628ED680700A6405A /* WalletOpener.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBB509D528ED680700A6405A /* WalletOpener.swift */; };
2222
BBB509D828ED682000A6405A /* OpenWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBB509D728ED681F00A6405A /* OpenWalletView.swift */; };
23+
BBB9FD232C2D4F1B008FD38D /* RequestProofView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBB9FD222C2D4F1B008FD38D /* RequestProofView.swift */; };
2324
BBD7B25127181C4300C3FB6C /* QRCodeHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBD7B25027181C4300C3FB6C /* QRCodeHandler.swift */; };
2425
/* End PBXBuildFile section */
2526

@@ -37,6 +38,7 @@
3738
BB90F26628F92DA10066AE87 /* local-genesis.txn */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "local-genesis.txn"; sourceTree = "<group>"; };
3839
BBB509D528ED680700A6405A /* WalletOpener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletOpener.swift; sourceTree = "<group>"; };
3940
BBB509D728ED681F00A6405A /* OpenWalletView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenWalletView.swift; sourceTree = "<group>"; };
41+
BBB9FD222C2D4F1B008FD38D /* RequestProofView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestProofView.swift; sourceTree = "<group>"; };
4042
BBD7B25027181C4300C3FB6C /* QRCodeHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeHandler.swift; sourceTree = "<group>"; };
4143
/* End PBXFileReference section */
4244

@@ -94,6 +96,7 @@
9496
BB5C4680270C1501008D77AE /* WalletMainView.swift */,
9597
BBB509D528ED680700A6405A /* WalletOpener.swift */,
9698
BBB509D728ED681F00A6405A /* OpenWalletView.swift */,
99+
BBB9FD222C2D4F1B008FD38D /* RequestProofView.swift */,
97100
BB5C468C270C390E008D77AE /* CredentialListView.swift */,
98101
BB5C468E270C4181008D77AE /* CredentialDetailView.swift */,
99102
BBD7B25027181C4300C3FB6C /* QRCodeHandler.swift */,
@@ -202,6 +205,7 @@
202205
files = (
203206
BBB509D828ED682000A6405A /* OpenWalletView.swift in Sources */,
204207
BBD7B25127181C4300C3FB6C /* QRCodeHandler.swift in Sources */,
208+
BBB9FD232C2D4F1B008FD38D /* RequestProofView.swift in Sources */,
205209
BB5C468D270C390E008D77AE /* CredentialListView.swift in Sources */,
206210
BB5C4681270C1501008D77AE /* WalletMainView.swift in Sources */,
207211
BB5C468F270C4181008D77AE /* CredentialDetailView.swift in Sources */,
@@ -336,13 +340,14 @@
336340
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
337341
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
338342
CODE_SIGN_IDENTITY = "Apple Development";
339-
CODE_SIGN_STYLE = Manual;
343+
CODE_SIGN_STYLE = Automatic;
340344
CURRENT_PROJECT_VERSION = 1;
341345
DEVELOPMENT_ASSET_PATHS = "\"wallet-app-ios/Preview Content\"";
342-
DEVELOPMENT_TEAM = "";
346+
DEVELOPMENT_TEAM = RAZ4DT76QQ;
343347
ENABLE_BITCODE = NO;
344348
ENABLE_PREVIEWS = YES;
345349
GENERATE_INFOPLIST_FILE = YES;
350+
INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "Need bluetooth for proof exchange";
346351
INFOPLIST_KEY_NSCameraUsageDescription = "Use camera to scan QR Code";
347352
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
348353
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
@@ -356,7 +361,7 @@
356361
"@executable_path/Frameworks",
357362
);
358363
MARKETING_VERSION = 1.0;
359-
PRODUCT_BUNDLE_IDENTIFIER = "org.hyperledger.aries.demo.wallet-app-ios";
364+
PRODUCT_BUNDLE_IDENTIFIER = "org.hyperledger.aries.demo.wallet-app-ios2";
360365
PRODUCT_NAME = "$(TARGET_NAME)";
361366
PROVISIONING_PROFILE_SPECIFIER = "";
362367
SWIFT_EMIT_LOC_STRINGS = YES;
@@ -371,13 +376,14 @@
371376
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
372377
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
373378
CODE_SIGN_IDENTITY = "Apple Development";
374-
CODE_SIGN_STYLE = Manual;
379+
CODE_SIGN_STYLE = Automatic;
375380
CURRENT_PROJECT_VERSION = 1;
376381
DEVELOPMENT_ASSET_PATHS = "\"wallet-app-ios/Preview Content\"";
377-
DEVELOPMENT_TEAM = "";
382+
DEVELOPMENT_TEAM = RAZ4DT76QQ;
378383
ENABLE_BITCODE = NO;
379384
ENABLE_PREVIEWS = YES;
380385
GENERATE_INFOPLIST_FILE = YES;
386+
INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "Need bluetooth for proof exchange";
381387
INFOPLIST_KEY_NSCameraUsageDescription = "Use camera to scan QR Code";
382388
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
383389
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
@@ -391,7 +397,7 @@
391397
"@executable_path/Frameworks",
392398
);
393399
MARKETING_VERSION = 1.0;
394-
PRODUCT_BUNDLE_IDENTIFIER = "org.hyperledger.aries.demo.wallet-app-ios";
400+
PRODUCT_BUNDLE_IDENTIFIER = "org.hyperledger.aries.demo.wallet-app-ios2";
395401
PRODUCT_NAME = "$(TARGET_NAME)";
396402
PROVISIONING_PROFILE_SPECIFIER = "";
397403
SWIFT_EMIT_LOC_STRINGS = YES;

Diff for: Sample/wallet-app-ios.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

+65-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
"kind" : "remoteSourceControl",
66
"location" : "https://github.com/hyperledger/aries-uniffi-wrappers",
77
"state" : {
8-
"revision" : "f335e392d6c5b8bd4dfa65746f214b80cdc60551",
9-
"version" : "0.2.0"
8+
"revision" : "01def706b44a4095032cd42f0480a5bdfb809961",
9+
"version" : "0.2.1"
1010
}
1111
},
1212
{
@@ -27,6 +27,15 @@
2727
"version" : "3.1.0"
2828
}
2929
},
30+
{
31+
"identity" : "blueswift",
32+
"kind" : "remoteSourceControl",
33+
"location" : "https://github.com/conanoc/BlueSwift",
34+
"state" : {
35+
"revision" : "5c9cc238396061bf7f3d6056dc8fdfe060a1add3",
36+
"version" : "1.1.7"
37+
}
38+
},
3039
{
3140
"identity" : "cocoaasyncsocket",
3241
"kind" : "remoteSourceControl",
@@ -72,6 +81,24 @@
7281
"version" : "1.1.0"
7382
}
7483
},
84+
{
85+
"identity" : "didcore-swift",
86+
"kind" : "remoteSourceControl",
87+
"location" : "https://github.com/beatt83/didcore-swift.git",
88+
"state" : {
89+
"revision" : "2503b1690e11b16a0cdc8f492e370bbd9dcbe08b",
90+
"version" : "2.0.0"
91+
}
92+
},
93+
{
94+
"identity" : "peerdid-swift",
95+
"kind" : "remoteSourceControl",
96+
"location" : "https://github.com/beatt83/peerdid-swift",
97+
"state" : {
98+
"revision" : "4e82ff42aa2b53b2d361f482b607763d79ccfdbb",
99+
"version" : "3.0.0"
100+
}
101+
},
75102
{
76103
"identity" : "semaphore",
77104
"kind" : "remoteSourceControl",
@@ -89,6 +116,42 @@
89116
"revision" : "e325083424688055363bbfcb7f1a440d7d7a1bae",
90117
"version" : "1.2.2"
91118
}
119+
},
120+
{
121+
"identity" : "swift-algorithms",
122+
"kind" : "remoteSourceControl",
123+
"location" : "https://github.com/apple/swift-algorithms",
124+
"state" : {
125+
"revision" : "f6919dfc309e7f1b56224378b11e28bab5bccc42",
126+
"version" : "1.2.0"
127+
}
128+
},
129+
{
130+
"identity" : "swift-bases",
131+
"kind" : "remoteSourceControl",
132+
"location" : "https://github.com/swift-libp2p/swift-bases.git",
133+
"state" : {
134+
"revision" : "3cf27cf95d70248b0a1d99eee06cdf8b235241a8",
135+
"version" : "0.0.3"
136+
}
137+
},
138+
{
139+
"identity" : "swift-multibase",
140+
"kind" : "remoteSourceControl",
141+
"location" : "https://github.com/swift-libp2p/swift-multibase.git",
142+
"state" : {
143+
"revision" : "45f3cf2844477b9d211e1d3e793d0853134fd942",
144+
"version" : "0.0.2"
145+
}
146+
},
147+
{
148+
"identity" : "swift-numerics",
149+
"kind" : "remoteSourceControl",
150+
"location" : "https://github.com/apple/swift-numerics.git",
151+
"state" : {
152+
"revision" : "0a5bc04095a675662cf24757cc0640aa2204253b",
153+
"version" : "1.0.2"
154+
}
92155
}
93156
],
94157
"version" : 2

Diff for: Sample/wallet-app-ios/CredentialHandler.swift

+18-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ extension CredentialHandler: AgentDelegate {
3737
} else if proofRecord.state == .Done {
3838
menu = nil
3939
showSimpleAlert(message: "Proof done")
40+
} else if proofRecord.state == .PresentationReceived {
41+
menu = nil
42+
showSimpleAlert(message: "Proof.isVerified: \(proofRecord.isVerified!)")
43+
} else if proofRecord.state == .PresentationSent {
44+
menu = nil
45+
showSimpleAlert(message: "Proof sent")
4046
}
4147
}
4248
}
@@ -88,7 +94,7 @@ extension CredentialHandler: AgentDelegate {
8894
_ = try await agent!.proofs.acceptRequest(proofRecordId: proofRecordId, requestedCredentials: requestedCredentials)
8995
} catch {
9096
menu = nil
91-
showSimpleAlert(message: "Failed to present proof")
97+
showSimpleAlert(message: "Failed to present proof: \(error)")
9298
print(error)
9399
}
94100
}
@@ -110,4 +116,15 @@ extension CredentialHandler: AgentDelegate {
110116
self?.showAlert = true
111117
}
112118
}
119+
120+
func createProofInvitation() async throws -> String {
121+
let attributes = ["attrbutes1": ProofAttributeInfo(names: ["name", "degree"])]
122+
let nonce = try ProofService.generateProofRequestNonce()
123+
let proofRequest = ProofRequest(nonce: nonce, requestedAttributes: attributes, requestedPredicates: [:])
124+
let (message, _) = try await agent!.proofService.createRequest(proofRequest: proofRequest)
125+
let outOfBandRecord = try await agent!.oob.createInvitation(
126+
config: CreateOutOfBandInvitationConfig(handshake: false, messages: [message]))
127+
let invitation = outOfBandRecord.outOfBandInvitation
128+
return try invitation.toUrl(domain: "http://example.com")
129+
}
113130
}

Diff for: Sample/wallet-app-ios/QRCodeHandler.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class QRCodeHandler {
1313
Task {
1414
do {
1515
let (_, connection) = try await agent!.oob.receiveInvitationFromUrl(url)
16-
await credentialHandler.showSimpleAlert(message: "Connected with \(connection?.theirLabel ?? "unknown agent")")
16+
print("Connected with \(connection?.theirLabel ?? "unknown agent")")
1717
} catch {
1818
print(error)
1919
await credentialHandler.reportError()

0 commit comments

Comments
 (0)