From 1043a4d2fd5e0d473e67d1d226962f2d1d11da77 Mon Sep 17 00:00:00 2001 From: Fortune Ikechi Date: Thu, 23 Apr 2026 15:16:35 +0100 Subject: [PATCH 01/12] update the multipeer pages to includes bluetooth --- modules/android/pages/p2psync-multipeer.adoc | 145 +++++++++++++++--- modules/android/pages/p2psync-websocket.adoc | 39 ++--- .../pages/p2psync-websocket-using-active.adoc | 6 +- modules/swift/pages/p2psync-multipeer.adoc | 129 +++++++++++++--- modules/swift/pages/p2psync-websocket.adoc | 29 ++-- 5 files changed, 271 insertions(+), 77 deletions(-) diff --git a/modules/android/pages/p2psync-multipeer.adoc b/modules/android/pages/p2psync-multipeer.adoc index 4785f2f93..9e7386145 100644 --- a/modules/android/pages/p2psync-multipeer.adoc +++ b/modules/android/pages/p2psync-multipeer.adoc @@ -1,6 +1,6 @@ = Multipeer P2P Replicator ifdef::show_edition[:page-edition: Enterprise Edition] -:description: The Multipeer Replicator enables lightweight, self-organizing mesh networks for apps running on the same local Wi-Fi. +:description: The Multipeer Replicator enables lightweight, self-organizing mesh networks over Wi-Fi and Bluetooth Low Energy. :source-language: Kotlin @@ -16,7 +16,7 @@ This approach requires minimal setup and automates peer discovery and connectivi Couchbase Lite's Peer-to-Peer synchronization solution offers secure storage and bidirectional data synchronization between mobile and IoT devices without needing a centralized cloud-based control point. -For small mesh topologies, Multipeer Replicator offers `autodiscovery` for Wi-Fi-based networks and secure communication via TLS and certificate-based authentication. +For small mesh topologies, Multipeer Replicator offers autodiscovery over Wi-Fi and Bluetooth Low Energy, with secure communication via TLS and certificate-based authentication. The dynamic mesh topology gives optimal peer connectivity and the lightweight and low-maintenance configuration requires less management and less code than using active-passive peer-to-peer sync. @@ -24,7 +24,7 @@ The dynamic mesh topology gives optimal peer connectivity and the lightweight an To maintain optimal connectivity, efficient data transport, and balanced workloads, the Multipeer Replicator forms a dynamic mesh network among peers in the same group. -The mesh network provides resilience through multiple communication pathways - if one connection fails, data can flow through alternative routes. +The mesh network provides resilience through multiple communication pathways. If one connection fails, data can flow through alternative routes. It avoids redundant direct connections, evenly distributes connections across peers, and optimizes communication paths through intelligent routing. @@ -32,8 +32,6 @@ The mesh network continuously adapts as peers join or leave, automatically heali This self-organizing approach ensures reliable data synchronization even in challenging network conditions, where individual peer connections may be intermittent or unreliable. -Multipeer Replicator supports Wi-Fi (IP-based transport) as of CBL 3.3. - // Mesh Diagram // [graphviz] // .... @@ -66,19 +64,81 @@ Multipeer Replicator supports Wi-Fi (IP-based transport) as of CBL 3.3. == Prerequisites +The Multipeer Replicator supports two transports for peer discovery and replication: Wi-Fi and Bluetooth Low Energy (BLE). Wi-Fi is enabled by default. Bluetooth is optional and you enable it through the replicator configuration. See <>. -=== Transport and Peer Discovery Protocol +=== Transport Support +.Transport support +[cols="1,1,2,1,2"] +|=== +|Transport |Available from |Discovery |Minimum Android API |Notes -Multipeer Replicator supports Wi-Fi transport, using `DNS-SD` (also known as Bonjour) for peer discovery. -Peers connect to the same Wi-Fi network to discover and establish connections with one another. +|Wi-Fi +|CBL 3.3 +|DNS-SD (Bonjour) +|API 24 +|Peers must connect to the same Wi-Fi network. +|Bluetooth Low Energy +|CBL 4.1 +|BLE advertising and scanning +|API 29 +|Requires additional manifest permissions and runtime permission requests. See <>. +|=== === Supported Platforms +For Wi-Fi transport, CBL supports Android API 24 and higher. + +For Bluetooth transport, CBL supports Android API 29 and higher. On API 29 and 30, Bluetooth uses the legacy `BLUETOOTH`, `BLUETOOTH_ADMIN`, and `ACCESS_FINE_LOCATION` permissions. On API 31 and higher, Bluetooth uses the runtime permissions `BLUETOOTH_SCAN`, `BLUETOOTH_ADVERTISE`, and `BLUETOOTH_CONNECT`. + +See xref:android:supported-os.adoc[Supported Platforms] for the full platform support matrix. + +[#platform-configuration] +=== Platform Configuration + +This section applies only if your application enables Bluetooth transport. Applications that use Wi-Fi only do not require these permissions. + +==== Manifest Permissions + +Declare the required Bluetooth permissions in your `AndroidManifest.xml`. The permissions differ between Android 11 (API 30) and lower, and Android 12 (API 31) and higher. + +[source,xml] +---- + + + + + + + + + + + + + +---- + +==== Runtime Permission Request -For Android, we recommend using a recent release, preferably supporting minimum API level 24, or more recent but earlier versions should work with the multipeer sync feature. -See xref:kotlin:supported-os.adoc[Supported Platforms] for more details. +On Android 12 (API 31) and higher, your application must request `BLUETOOTH_SCAN`, `BLUETOOTH_ADVERTISE`, and `BLUETOOTH_CONNECT` at runtime before starting the Multipeer Replicator. On Android 11 (API 30) and lower, your application must request `ACCESS_FINE_LOCATION` at runtime. + +.Requesting Bluetooth permissions at runtime +[source,kotlin] +---- +include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-bluetooth-permissions-request", indent=0] +---- == Configuration @@ -167,6 +227,33 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-authenticator-rootcerts", indent=0] ---- +[#transports] +=== Transports + +The `transports` property on `MultipeerReplicatorConfiguration` controls which transports the replicator uses for peer discovery and replication. The default is Wi-Fi only. + +To enable Bluetooth Low Energy alongside Wi-Fi, add `MultipeerTransport.BLUETOOTH` to the transports set. + +.Default (Wi-Fi only) +[source,kotlin] +---- +include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-config-transports-default", indent=0] +---- + +.Wi-Fi and Bluetooth +[source,kotlin] +---- +include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-config-transports-both", indent=0] +---- + +.Bluetooth only +[source,kotlin] +---- +include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-config-transports-bluetooth-only", indent=0] +---- + +When you enable both transports, the replicator automatically selects the best available transport for each peer and switches between them as reachability changes. See <>. + === Create MultipeerReplicatorConfiguration @@ -182,6 +269,25 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ TIP: Performance may vary in mesh networks depending on your specific environment and number of peers. We recommend running tests with your network configuration to assess any effects on packet loss or latency. +[#automatic-transport-switching] +== Automatic Transport Switching + +When `MultipeerReplicator` is configured with both Wi-Fi and Bluetooth transports, it automatically selects the best available transport for each peer and switches transports as reachability changes. + +=== Transport Preference + +The replicator prefers Wi-Fi over Bluetooth when both transports can reach a peer. Bluetooth acts as a fallback when Wi-Fi cannot reach a peer. + +=== Fallback to Bluetooth + +For an individual peer, `MultipeerReplicator` falls back to Bluetooth when the peer is no longer reachable over Wi-Fi. This can occur if the peer disables Wi-Fi, becomes unreachable on the local network, or if replication over Wi-Fi fails because of a network-related error. + +In cases of connection or replication failure over Wi-Fi, `MultipeerReplicator` performs a small number of retries before falling back to Bluetooth. + +=== Return to Wi-Fi + +If a peer becomes reachable over Wi-Fi while replication is active over Bluetooth, `MultipeerReplicator` establishes a Wi-Fi connection in parallel with the existing Bluetooth connection. The Bluetooth connection remains active until the Wi-Fi connection is fully established and replication has resumed over Wi-Fi. This prevents any interruption in synchronization during the transition. + == Life Cycle @@ -240,6 +346,9 @@ You should make sure that the application has the necessary permissions to run i === Events In general, the connection should just work, and most of these optional listen events give status you may only want to use during development and testing. + +Status events include a `transport` property that identifies which transport the event applies to. `MultipeerReplicatorStatus` events are delivered per enabled transport and also as an aggregated status (where `transport` is `null`) representing the overall replicator state. + Event types include the following: @@ -319,8 +428,9 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ === Peer Info +The `PeerInfo` object provides information about a peer, including its identifier, certificate, online status, replicator status, neighbor peers, the transports on which the peer was discovered, and the transport currently used for replication. -Getting peer info +.Getting peer info [source,kotlin] ---- include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-peer-info", indent=0] @@ -346,7 +456,7 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ == API Reference -You can find https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-kotlin}{empty}/couchbase-lite-kotlin[Kotlin API References] here. +You can find https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-android}/couchbase-lite-android[Kotlin API References] here. @@ -604,14 +714,14 @@ You can find https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-kotl // /// The `attributes` must include a common name (CN); otherwise an error // /// will be thrown. // /// -// /// If no the expiration date is specified, the default validity of one year -// /// will be applied. -// /// // /// The optional issuer identity may be specified to sign the certificate. // /// The issuer identity can be created using // /// `createIdentity(privateKeyData:certificateData:)`. If no issuer is specified, // /// the certificate will be self-signed. // /// +// /// If no the expiration date is specified, the default validity of one year +// /// will be applied. +// /// // /// If a `label` is provided, the identity will be stored in the // /// platform’s secure key storage under that label. // public static func createIdentity(keyUsages: KeyUsages, @@ -651,7 +761,4 @@ You can find https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-kotl // == API Reference -// *URL* - - - +// *URL* \ No newline at end of file diff --git a/modules/android/pages/p2psync-websocket.adoc b/modules/android/pages/p2psync-websocket.adoc index 5d72796db..827824a53 100644 --- a/modules/android/pages/p2psync-websocket.adoc +++ b/modules/android/pages/p2psync-websocket.adoc @@ -25,7 +25,8 @@ xref:p2psync-multipeer.adoc[Multipeer P2P Replicator] ==== Multipeer P2P Replicator is available for Android, offering: -* Auto-discovery over local Wi-Fi (via `DNS-SD`) +* Auto-discovery over Wi-Fi and Bluetooth Low Energy +* Automatic transport switching between Wi-Fi and Bluetooth when both are enabled * Lightweight and low-maintenance configuration * Dynamic mesh topology for optimal peer connectivity * Secure communication via TLS and certificate-based authentication @@ -76,7 +77,7 @@ Therefore, to use Peer-to-Peer synchronization in your application, you must con . Point the replicator at the Listener . Initialize the replicator + . Replicator and Listener engage in the configured security protocol exchanges to confirm connection -. If connection is confirmed then replication will commence, synchronizing the two data stores. +. If connection is confirmed then replication commences, synchronizing the two data stores. ==== @@ -101,8 +102,8 @@ Having a Listener on a database still allows you to open replications to the oth For example, a Listener can actively begin replicating to other Listeners while listening for connections. These replications can be for the same or a different database. -The Listener will automatically select a port to use or a user-specified port. -It will also listen on all available networks, unless you specify a specific network. +The Listener automatically selects a port to use or a user-specified port. +It also listens on all available networks, unless you specify a specific network. [#security] === Security @@ -126,17 +127,19 @@ For testing and development purposes, support is provided for the client (active [#error-handling] === Error Handling -When a Listener is stopped, then all connected replicators are notified by a WebSocket error. Your application should distinguish between transient and permanent connectivity errors. +When a Listener is stopped, then all connected replicators are notified by a WebSocket error. +Your application should distinguish between transient and permanent connectivity errors. [#passive-peers] ==== Passive peers -A Passive Peer losing connectivity with an Active Peer will clean up any associated endpoint connections to that Peer. The Active Peer may attempt to reconnect to the Passive Peer. +A Passive Peer losing connectivity with an Active Peer cleans up any associated endpoint connections to that Peer. +The Active Peer may attempt to reconnect to the Passive Peer. [#active-peers] ==== Active peers -An Active Peer permanently losing connectivity with a Passive Peer will cease replicating. +An Active Peer permanently losing connectivity with a Passive Peer ceases replicating. -An Active Peer temporarily losing connectivity with a passive Peer will use exponential backoff functionality to attempt reconnection. +An Active Peer temporarily losing connectivity with a passive Peer uses exponential backoff feature to attempt reconnection. [#delta-sync] === Delta Sync @@ -162,7 +165,7 @@ You can configure a Peer-to-Peer synchronization with just a short amount of cod [#ex-simple-listener] ==== -This simple listener configuration will give you a listener ready to participate in an encrypted synchronization with a replicator providing a valid user name and password. +This simple listener configuration gives you a listener ready to participate in an encrypted synchronization with a replicator providing a valid user name and password. [tabs] ===== @@ -205,7 +208,7 @@ include::android:example$codesnippet_collection.java[tags="listener-simple", ind [#ex-simple-replicator] ==== -This simple replicator configuration will give you an encrypted, bi-directional Peer-to-Peer synchronization with automatic conflict resolution. +This simple replicator configuration gives you an encrypted, bi-directional Peer-to-Peer synchronization with automatic conflict resolution. [tabs] ===== @@ -270,9 +273,9 @@ Use this to create a configuration object you can then use to initialize the lis Port:: + -- -This is the port that the listener will listen to. +This is the port that the listener listens to. -If the port is null or zero, the listener will auto-assign an available port to listen on. +If the port is null or zero, the listener auto-assigns an available port to listen on. Default value is null or zero depending on platform. When the listener is not started, the port is null (or zero if the platform requires). @@ -283,7 +286,7 @@ Network Interface:: -- Use this to select a specific Network Interface to use, in the form of the IP Address or network interface name. -If the network interface is specified, only that interface wil be used. +If the network interface is specified, only that interface will be used. If the network interface is not specified, all available network interfaces will be used. @@ -306,7 +309,7 @@ https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-android}{empty}/c Active peers will use the `ws://` URL scheme used to connect to the listener. * If `disableTLS` is false or not specified -- TLS communication is enabled. + -Active peers will use the `wss://` URL scheme to connect to the listener. +Active peers uses the `wss://` URL scheme to connect to the listener. // end::config-disable-tls[] API Reference: https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-android}{empty}/couchbase-lite-android/com/couchbase/lite/URLEndpointListenerConfiguration.html#setDisableTls-boolean-[setDisableTLS] @@ -320,7 +323,7 @@ Use https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-android}{empt https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-android}{empty}/couchbase-lite-android/com/couchbase/lite/URLEndpointListenerConfiguration.html#setTlsIdentity-com.couchbase.lite.TLSIdentity-[setTlsIdentity] method to configure the TLS Identity used in TLS communication. If `TLSIdentity` is not set, then the listener uses an auto-generated anonymous self-signed identity (unless `disableTLS = true`). -Whilst the client cannot use this to authenticate the server, it will use it to encrypt communication, giving a more secure option than non-TLS communication. +Whilst the client cannot use this to authenticate the server, it uses it to encrypt communication, giving a more secure option than non-TLS communication. The auto-generated anonymous self-signed identity is saved in secure storage for future use to obviate the need to re-generate it. @@ -426,7 +429,7 @@ Please check this document for more info: https://source.android.com/security/ke -- -MacOS / iOS:: +MacOS / iOS:: + -- .Secure storage details @@ -586,6 +589,4 @@ xref:tutorials:cbl-p2p-sync-websockets:swift/cbl-p2p-sync-websockets.adoc[Gettin ++++ -++++ - - +++++ \ No newline at end of file diff --git a/modules/objc/pages/p2psync-websocket-using-active.adoc b/modules/objc/pages/p2psync-websocket-using-active.adoc index e9ffb0485..d2b9d2546 100644 --- a/modules/objc/pages/p2psync-websocket-using-active.adoc +++ b/modules/objc/pages/p2psync-websocket-using-active.adoc @@ -426,10 +426,10 @@ Use this to monitor changes and to inform on sync progress; this is an optional You can add and a replicator change listener at any point; it will report changes from the point it is registered. .Best Practice -TIP: Don't forget to save the token so you can remove the listener later +TIP: Do not forget to save the token so you can remove the listener later Use the https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-ios}{empty}/couchbase-lite-objc/Classes/CBLReplicator.html[Replicator] class to add a change listener as a callback to the Replicator (https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-ios}{empty}/couchbase-lite-objc/Classes/CBLReplicator.html#/c:objc(cs)CBLReplicator(im)addChangeListener:[addChangeListener(_:)]) -- see: <>. -You will then be asynchronously notified of state changes. +You are then asynchronously notified of state changes. You can remove a change listener with https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-ios}{empty}/couchbase-lite-objc/Classes/CBLReplicator.html#/c:objc(cs)CBLReplicator(im)removeChangeListenerWithToken[removeChangeListenerWithToken(CBLListenerToken:)]. @@ -440,7 +440,7 @@ You can remove a change listener with https://docs.couchbase.com/mobile/{major}. You can use the https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-ios}{empty}/couchbase-lite-objc/Classes/CBLReplicatorStatus.html[CBLReplicatorStatus] class to check the replicator status. -That is, whether it is actively transferring data or if it has stopped -- see: <>. +That's, whether it's actively transferring data or if it has stopped -- see: <>. The returned _ReplicationStatus_ structure comprises: diff --git a/modules/swift/pages/p2psync-multipeer.adoc b/modules/swift/pages/p2psync-multipeer.adoc index 0014ae233..003b0dd0b 100644 --- a/modules/swift/pages/p2psync-multipeer.adoc +++ b/modules/swift/pages/p2psync-multipeer.adoc @@ -1,6 +1,6 @@ = Multipeer P2P Replicator ifdef::show_edition[:page-edition: Enterprise Edition] -:description: The Multipeer Replicator enables lightweight, self-organizing mesh networks for apps running on the same local Wi-Fi. +:description: The Multipeer Replicator enables lightweight, self-organizing mesh networks over Wi-Fi and Bluetooth Low Energy. :source-language: swift @@ -15,7 +15,7 @@ This approach requires minimal setup and automates peer discovery and connectivi // tag::introduction[] Couchbase Lite's Peer-to-Peer synchronization solution offers secure storage and bidirectional data synchronization between mobile and IoT devices without needing a centralized cloud-based control point. -For small mesh topologies, Multipeer Replicator offers `autodiscovery` for Wi-Fi-based networks and secure communication via TLS and certificate-based authentication. +For small mesh topologies, Multipeer Replicator offers autodiscovery over Wi-Fi and Bluetooth Low Energy, with secure communication via TLS and certificate-based authentication. The dynamic mesh topology gives optimal peer connectivity and the lightweight and low-maintenance configuration requires less management and less code than using active-passive peer-to-peer sync. // end::introduction[] @@ -25,15 +25,14 @@ The dynamic mesh topology gives optimal peer connectivity and the lightweight an == Overview To maintain optimal connectivity, efficient data transport, and balanced workloads, the Multipeer Replicator forms a dynamic mesh network among peers in the same group. -The mesh network provides resilience through multiple communication pathways - if one connection fails, data can flow through alternative routes. +The mesh network provides resilience through multiple communication pathways. +If one connection fails, data can flow through alternative routes. It avoids redundant direct connections, evenly distributes connections across peers, and optimizes communication paths through intelligent routing. The mesh network continuously adapts as peers join or leave, automatically healing itself by establishing new connections and rerouting data flow to maintain network integrity. This self-organizing approach ensures reliable data synchronization even in challenging network conditions, where individual peer connections may be intermittent or unreliable. -Multipeer Replicator supports Wi-Fi (IP-based transport) as of CBL 3.3. - // Mesh Diagram @@ -69,19 +68,48 @@ Multipeer Replicator supports Wi-Fi (IP-based transport) as of CBL 3.3. == Prerequisites -=== Transport and Peer Discovery Protocol +The Multipeer Replicator supports two transports for peer discovery and replication: Wi-Fi and Bluetooth Low Energy (BLE). Wi-Fi is enabled by default. +Bluetooth is optional and you enable it through the replicator configuration. +See <>. + +=== Transport Support + +.Transport support +[cols="1,1,2,1,2"] +|=== +|Transport |Available from |Discovery |Minimum iOS |Notes + +|Wi-Fi +|CBL 3.3 +|DNS-SD (Bonjour) +|iOS 10 +|Peers must connect to the same Wi-Fi network. Requires `NSBonjourServices` and `NSLocalNetworkUsageDescription` in `Info.plist`. See <>. + +|Bluetooth Low Energy +|CBL 4.1 +|BLE advertising and scanning +|iOS 15 +|Requires `NSBluetoothAlwaysUsageDescription` in `Info.plist`. See <>. +|=== + +=== Supported Platforms + +For Wi-Fi transport, CBL supports iOS 10 and higher. + +For Bluetooth transport, CBL supports iOS 15 and higher. -Multipeer Replicator supports Wi-Fi transport, using `DNS-SD` (also known as *Bonjour*) for peer discovery. -You must connect Peers to the same Wi-Fi network to discover and establish connections with one another. +See xref:swift:supported-os.adoc[Supported Platforms] for the full platform support matrix. -=== Configuration Requirements +[#platform-configuration] +=== Platform Configuration -To use `DNS-SD` for peer discovery, iOS apps must declare the *Bonjour* service type and request local network access permissions. -Add the following keys to your app's `Info.plist`: +iOS applications must declare the required keys in `Info.plist` for each transport they enable. You can also configure these settings through Xcode's Info configuration UI. -==== NSBonjourServices -Declare the service type used by MultipeerReplicator: +==== Wi-Fi Transport +To use Wi-Fi transport, declare the Bonjour service type and a local network usage description. + +.NSBonjourServices [source,xml] ---- NSBonjourServices @@ -90,21 +118,23 @@ Declare the service type used by MultipeerReplicator: ---- -==== NSLocalNetworkUsageDescription -Add a usage description for local network access: - +.NSLocalNetworkUsageDescription [source,xml] ---- NSLocalNetworkUsageDescription Used for discovering and connecting to peers for peer-to-peer sync. ---- -TIP: You can also configure these settings through Xcode's Info configuration UI under "*Bonjour Services*" and "*Privacy – Local Network Usage Description*." +==== Bluetooth Transport +To use Bluetooth transport, declare a Bluetooth usage description. -=== Supported Platforms - -We recommend using a recent release of iOS, see xref:swift:supported-os.adoc[Supported Platforms] for details. +.NSBluetoothAlwaysUsageDescription +[source,xml] +---- +NSBluetoothAlwaysUsageDescription +Used for discovering and connecting to peers for peer-to-peer sync. +---- == Configuration @@ -186,6 +216,35 @@ include::swift:example$code_snippets/MultipeerReplicator.swift[tags="multipeer-a include::swift:example$code_snippets/MultipeerReplicator.swift[tags="multipeer-authenticator-rootcerts", indent=0] ---- +[#transports] +=== Transports + +The `transports` property on `MultipeerReplicatorConfiguration` controls which transports the replicator uses for peer discovery and replication. +The default is Wi-Fi only. + +To enable Bluetooth Low Energy alongside Wi-Fi, add `.bluetooth` to the transports set. + +.Default (Wi-Fi only) +[source,swift] +---- +include::swift:example$code_snippets/MultipeerReplicator.swift[tags="multipeer-config-transports-default", indent=0] +---- + +.Wi-Fi and Bluetooth +[source,swift] +---- +include::swift:example$code_snippets/MultipeerReplicator.swift[tags="multipeer-config-transports-both", indent=0] +---- + +.Bluetooth only +[source,swift] +---- +include::swift:example$code_snippets/MultipeerReplicator.swift[tags="multipeer-config-transports-bluetooth-only", indent=0] +---- + +When you enable both transports, the replicator automatically selects the best available transport for each peer and switches between them as reachability changes. +See <>. + === Create MultipeerReplicatorConfiguration The `MultipeerReplicatorConfiguration` can be created with a `peerGroupID` which is an identity identifies the Peer-to-peer network used by the app, collection configurations, peer identity, and authenticator. @@ -200,6 +259,29 @@ include::swift:example$code_snippets/MultipeerReplicator.swift[tags="multipeer-c TIP: Performance may vary in mesh networks depending on your specific environment and number of peers. We recommend running tests with your network configuration to assess any effects on packet loss or latency. +[#automatic-transport-switching] +== Automatic Transport Switching + +When `MultipeerReplicator` is configured with both Wi-Fi and Bluetooth transports, it automatically selects the best available transport for each peer and switches transports as reachability changes. + +=== Transport Preference + +The replicator prefers Wi-Fi over Bluetooth when both transports can reach a peer. +Bluetooth acts as a fallback when Wi-Fi cannot reach a peer. + +=== Fallback to Bluetooth + +For an individual peer, `MultipeerReplicator` falls back to Bluetooth when the peer is no longer reachable over Wi-Fi. +This can occur if the peer disables Wi-Fi, becomes unreachable on the local network, or if replication over Wi-Fi fails because of a network-related error. + +In cases of connection or replication failure over Wi-Fi, `MultipeerReplicator` performs a small number of retries before falling back to Bluetooth. + +=== Return to Wi-Fi + +If a peer becomes reachable over Wi-Fi while replication is active over Bluetooth, `MultipeerReplicator` establishes a Wi-Fi connection in parallel with the existing Bluetooth connection. +The Bluetooth connection remains active until the Wi-Fi connection is fully established and replication has resumed over Wi-Fi. +This prevents any interruption in synchronization during the transition. + == Life Cycle @@ -230,6 +312,9 @@ include::swift:example$code_snippets/MultipeerReplicator.swift[tags="multipeer-r === Events In general, the connection should just work, and most of these optional listen events give status you may only want to use during development and testing. + +Status events include a `transport` property that identifies which transport the event applies to. `MultipeerReplicatorStatus` events are delivered per enabled transport and also as an aggregated status (where `transport` is `nil`) representing the overall replicator state. + Event types include the following: ==== Multipeer Replicator Status @@ -291,6 +376,8 @@ include::swift:example$code_snippets/MultipeerReplicator.swift[tags="multipeer-n === Peer Info +The `PeerInfo` object provides information about a peer, including its identifier, certificate, online status, replicator status, neighbor peers, the transports on which the peer was discovered, and the transport presently used for replication. + .Getting peer info [source,swift] ---- @@ -313,4 +400,4 @@ include::swift:example$code_snippets/MultipeerReplicator.swift[tags="multipeer-l == API Reference -You can find https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-swift}{empty}/couchbase-lite-swift[Swift API References] here. +You can find https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-swift}{empty}/couchbase-lite-swift[Swift API References] here. \ No newline at end of file diff --git a/modules/swift/pages/p2psync-websocket.adoc b/modules/swift/pages/p2psync-websocket.adoc index 79a1d779c..dc30802a2 100644 --- a/modules/swift/pages/p2psync-websocket.adoc +++ b/modules/swift/pages/p2psync-websocket.adoc @@ -20,12 +20,13 @@ Related Content -- https://docs.couchbase.com/mobile/{major}.{minor}.{maintenanc ==== xref:p2psync-multipeer.adoc[Multipeer P2P Replicator] is available for Swift, offering: -* Auto-discovery over local Wi-Fi (via `DNS-SD`) +* Auto-discovery over Wi-Fi and Bluetooth Low Energy +* Automatic transport switching between Wi-Fi and Bluetooth when both are enabled * Lightweight and low-maintenance configuration * Dynamic mesh topology for optimal peer connectivity * Secure communication via TLS and certificate-based authentication -For many use cases, this will be quicker to develop for than Active-Passive peer-to-peer sync. +For many use cases, this is quicker to develop for than Active-Passive peer-to-peer sync. ==== @@ -72,7 +73,7 @@ Therefore, to use Peer-to-Peer synchronization in your application, you must con . Point the replicator at the Listener . Initialize the replicator + . Replicator and Listener engage in the configured security protocol exchanges to confirm connection -. If connection is confirmed then replication will commence, synchronizing the two data stores. +. If connection is confirmed then replication commences, synchronizing the two data stores. ==== @@ -96,8 +97,8 @@ Having a Listener on a database still allows you to open replications to the oth For example, a Listener can actively begin replicating to other Listeners while listening for connections. These replications can be for the same or a different database. -The Listener will automatically select a port to use or a user-specified port. -It will also listen on all available networks, unless you specify a specific network. +The Listener automatically selects a port to use or a user-specified port. +It also listens on all available networks, unless you specify a specific network. [#security] === Security @@ -121,17 +122,19 @@ For testing and development purposes, support is provided for the client (active [#error-handling] === Error Handling -When a Listener is stopped, then all connected replicators are notified by a WebSocket error. Your application should distinguish between transient and permanent connectivity errors. +When a Listener is stopped, then all connected replicators are notified by a WebSocket error. +Your application should distinguish between transient and permanent connectivity errors. [#passive-peers] ==== Passive peers -A Passive Peer losing connectivity with an Active Peer will clean up any associated endpoint connections to that Peer. The Active Peer may attempt to reconnect to the Passive Peer. +A Passive Peer losing connectivity with an Active Peer cleans up any associated endpoint connections to that Peer. +The Active Peer may attempt to reconnect to the Passive Peer. [#active-peers] ==== Active peers -An Active Peer permanently losing connectivity with a Passive Peer will cease replicating. +An Active Peer permanently losing connectivity with a Passive Peer ceases replicating. -An Active Peer temporarily losing connectivity with a passive Peer will use exponential backoff functionality to attempt reconnection. +An Active Peer temporarily losing connectivity with a passive Peer uses exponential backoff feature to attempt reconnection. [#delta-sync] === Delta Sync @@ -384,7 +387,7 @@ Please check this document for more info: https://source.android.com/security/ke -- -MacOS / iOS:: +MacOS / iOS:: + -- .Secure storage details @@ -538,12 +541,8 @@ https://forums.couchbase.com/c/mobile/14[Mobile Forum] | https://blog.couchbase.com/[Blog] | https://docs.couchbase.com/tutorials/[Tutorials] -. -xref:tutorials:cbl-p2p-sync-websockets:swift/cbl-p2p-sync-websockets.adoc[Getting Started with Peer-to-Peer Synchronization] ++++ -++++ - - +++++ \ No newline at end of file From a46b8137e239dab91de0349217b71f37a83695f2 Mon Sep 17 00:00:00 2001 From: Fortune Ikechi Date: Fri, 24 Apr 2026 19:51:18 +0100 Subject: [PATCH 02/12] add obj-c multipeer and websocket pages --- modules/objc/nav-objc.adoc | 5 +- modules/objc/pages/p2psync-multipeer.adoc | 358 ++++++++++++++++++++++ modules/objc/pages/p2psync-websocket.adoc | 24 +- 3 files changed, 378 insertions(+), 9 deletions(-) create mode 100644 modules/objc/pages/p2psync-multipeer.adoc diff --git a/modules/objc/nav-objc.adoc b/modules/objc/nav-objc.adoc index a755ed40e..384397e5a 100644 --- a/modules/objc/nav-objc.adoc +++ b/modules/objc/nav-objc.adoc @@ -38,7 +38,8 @@ include::partial$_set_page_context_for_objc.adoc[] * xref:objc:landing-replications.adoc[Data Sync] ** xref:objc:dbreplica.adoc[Intra-device Sync] ** xref:objc:replication.adoc[Remote Sync Gateway] - ** xref:objc:p2psync-websocket.adoc[Peer-to-Peer] + ** xref:objc:p2psync-multipeer.adoc[Multipeer Peer-to-Peer Replicator] + ** xref:objc:p2psync-websocket.adoc[Active-Passive Peer-to-Peer] *** xref:objc:p2psync-websocket-using-passive.adoc[Passive Peer] *** xref:objc:p2psync-websocket-using-active.adoc[Active Peer] *** xref:objc:p2psync-custom.adoc[Integrate Custom Listener] @@ -60,4 +61,4 @@ include::partial$_set_page_context_for_objc.adoc[] ** xref:objc:compatibility.adoc[Compatibility] ** xref:objc:supported-os.adoc[Supported Platforms] - // * xref:objc:refer-glossary.adoc[Glossary] + // * xref:objc:refer-glossary.adoc[Glossary] \ No newline at end of file diff --git a/modules/objc/pages/p2psync-multipeer.adoc b/modules/objc/pages/p2psync-multipeer.adoc new file mode 100644 index 000000000..76ee9836f --- /dev/null +++ b/modules/objc/pages/p2psync-multipeer.adoc @@ -0,0 +1,358 @@ += Multipeer P2P Replicator +ifdef::show_edition[:page-edition: Enterprise Edition] +:description: The Multipeer Replicator enables lightweight, self-organizing mesh networks over Wi-Fi and Bluetooth Low Energy. +:source-language: objc + + +[abstract] +{description} +This approach requires minimal setup and automates peer discovery and connectivity management, making it simpler than xref:p2psync-websocket.adoc[active-passive P2P configurations]. + + +[#introduction] +== Introduction + +Couchbase Lite's Peer-to-Peer synchronization solution offers secure storage and bidirectional data synchronization between mobile and IoT devices without needing a centralized cloud-based control point. + +For small mesh topologies, Multipeer Replicator offers autodiscovery over Wi-Fi and Bluetooth Low Energy, with secure communication via TLS and certificate-based authentication. +The dynamic mesh topology gives optimal peer connectivity and the lightweight and low-maintenance configuration requires less management and less code than using active-passive peer-to-peer sync. + + +== Overview + +To maintain optimal connectivity, efficient data transport, and balanced workloads, the Multipeer Replicator forms a dynamic mesh network among peers in the same group. +The mesh network provides resilience through multiple communication pathways. If one connection fails, data can flow through alternative routes. +It avoids redundant direct connections, evenly distributes connections across peers, and optimizes communication paths through intelligent routing. + +The mesh network continuously adapts as peers join or leave, automatically healing itself by establishing new connections and rerouting data flow to maintain network integrity. + +This self-organizing approach ensures reliable data synchronization even in challenging network conditions, where individual peer connections may be intermittent or unreliable. + + +== Prerequisites + +The Multipeer Replicator supports two transports for peer discovery and replication: Wi-Fi and Bluetooth Low Energy (BLE). Wi-Fi is enabled by default. Bluetooth is optional and you enable it through the replicator configuration. See <>. + +=== Transport Support + +.Transport support +[cols="1,1,2,1,2"] +|=== +|Transport |Available from |Discovery |Minimum iOS |Notes + +|Wi-Fi +|CBL 3.3 +|DNS-SD (Bonjour) +|iOS 10 +|Peers must connect to the same Wi-Fi network. Requires `NSBonjourServices` and `NSLocalNetworkUsageDescription` in `Info.plist`. See <>. + +|Bluetooth Low Energy +|CBL 4.1 +|BLE advertising and scanning +|iOS 15 +|Requires `NSBluetoothAlwaysUsageDescription` in `Info.plist`. See <>. +|=== + +=== Supported Platforms + +For Wi-Fi transport, CBL supports iOS 10 and higher. + +For Bluetooth transport, CBL supports iOS 15 and higher. + +See xref:objc:supported-os.adoc[Supported Platforms] for the full platform support matrix. + +[#platform-configuration] +=== Platform Configuration + +iOS applications must declare the required keys in `Info.plist` for each transport they enable. You can also configure these settings through Xcode's Info configuration UI. + +==== Wi-Fi Transport + +To use Wi-Fi transport, declare the Bonjour service type and a local network usage description. + +.NSBonjourServices +[source,xml] +---- +NSBonjourServices + + _couchbaseP2P._tcp + +---- + +.NSLocalNetworkUsageDescription +[source,xml] +---- +NSLocalNetworkUsageDescription +Used for discovering and connecting to peers for peer-to-peer sync. +---- + +==== Bluetooth Transport + +To use Bluetooth transport, declare a Bluetooth usage description. + +.NSBluetoothAlwaysUsageDescription +[source,xml] +---- +NSBluetoothAlwaysUsageDescription +Used for discovering and connecting to peers for peer-to-peer sync. +---- + + +== Configuration + +=== Collection Configurations + +You can specify one or more collections available for replication when creating a `CBLMultipeerReplicatorConfiguration`. +For each collection, you create `CBLMultipeerCollectionConfiguration` with the collection object and optionally configure a custom conflict resolver or any replication filters you want to use for the collection. + + +.Specify collections without any configurations +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-collection-simple", indent=0] +---- + +.Specify collections with some configuration +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-collection-config", indent=0] +---- + +=== Peer Identity + +Each peer in the Multipeer replication is uniquely identified and authenticated by using a peer's certificate. + +Multipeer Replicator uses TLS communication by default and requires a `CBLTLSIdentity` object for specifying the identity. + +You can use either a self-signed certificate for the identity or have an authority or issuer sign the identity's certificate. +The choice depends on your specific security requirements and deployment environment. + +As each peer could be either a client or a server to the other peer in the Multipeer replication environment, you must create the identity's certificate with the extension key usages for both client and server authentication to allow either direction to authenticate the certificate. + +==== CA-Signed Identity + +When using a certificate authority (CA) signed identity, the issuer's certificate authenticates the connecting peer. + +.Get and Create an identity signed by an issuer +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-tlsidentity", indent=0] +---- + +==== Self-Signed Identity + +For environments where certificate authority management is not feasible, you can implement peer identity using self-signed certificates. +This approach is commonly used in closed network environments where devices need to authenticate with each other without external certificate authorities. + +.Creating a self-signed identity for peer authentication +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-selfsigned-tlsidentity", indent=0] +---- + +When using self-signed certificates, implement your own certificate validation logic in the authenticator callback to make sure only trusted peers can join your mesh network. + +=== Peer Authenticator + +`CBLMultipeerReplicator` only supports certificate based authentication. +You can specify the authenticator in two ways: + +* certificate authentication callback +* root certificates. + +When specifying the certificate authentication callback, the callback receives the remote peer's identity certificate. + +When specifying the root certificates, the Multipeer replicator automatically authenticates the remote peer's identity certificate by verifying whether one of the specified root certificates signed the certificate. + + +.Authenticator with authentication callback +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-authenticator-callback", indent=0] +---- + +.Authenticator with root certificates +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-authenticator-rootcerts", indent=0] +---- + +[#transports] +=== Transports + +The `transports` property on `CBLMultipeerReplicatorConfiguration` controls which transports the replicator uses for peer discovery and replication. The default is Wi-Fi only. + +The property type is `CBLMultipeerTransportSet`, an `NS_OPTIONS` bitmask. To enable Bluetooth Low Energy alongside Wi-Fi, combine the transport options with the bitwise OR operator. + +.Default (Wi-Fi only) +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-config-transports-default", indent=0] +---- + +.Wi-Fi and Bluetooth +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-config-transports-both", indent=0] +---- + +.Bluetooth only +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-config-transports-bluetooth-only", indent=0] +---- + +When you enable both transports, the replicator automatically selects the best available transport for each peer and switches between them as reachability changes. See <>. + +=== Create MultipeerReplicatorConfiguration + +The `CBLMultipeerReplicatorConfiguration` is created with a `peerGroupID` that identifies the peer-to-peer network used by the app, collection configurations, peer identity, and authenticator. + + +.Creating MultipeerReplicatorConfiguration +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-config", indent=0] +---- + +TIP: Performance may vary in mesh networks depending on your specific environment and number of peers. +We recommend running tests with your network configuration to assess any effects on packet loss or latency. + +[#automatic-transport-switching] +== Automatic Transport Switching + +When `CBLMultipeerReplicator` is configured with both Wi-Fi and Bluetooth transports, it automatically selects the best available transport for each peer and switches transports as reachability changes. + +=== Transport Preference + +The replicator prefers Wi-Fi over Bluetooth when both transports can reach a peer. Bluetooth acts as a fallback when Wi-Fi cannot reach a peer. + +=== Fallback to Bluetooth + +For an individual peer, `CBLMultipeerReplicator` falls back to Bluetooth when the peer is no longer reachable over Wi-Fi. This can occur if the peer disables Wi-Fi, becomes unreachable on the local network, or if replication over Wi-Fi fails because of a network-related error. + +In cases of connection or replication failure over Wi-Fi, `CBLMultipeerReplicator` performs a small number of retries before falling back to Bluetooth. + +=== Return to Wi-Fi + +If a peer becomes reachable over Wi-Fi while replication is active over Bluetooth, `CBLMultipeerReplicator` establishes a Wi-Fi connection in parallel with the existing Bluetooth connection. The Bluetooth connection remains active until the Wi-Fi connection is fully established and replication has resumed over Wi-Fi. This prevents any interruption in synchronization during the transition. + + +== Life Cycle + +=== Create MultipeerReplicator with Configuration + +.Creating MultipeerReplicator +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-replicator", indent=0] +---- + +=== Start + +.Starting MultipeerReplicator +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-replicator-start", indent=0] +---- + +=== Stop + +.Stopping MultipeerReplicator +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-replicator-stop", indent=0] +---- + +=== Events + +In general, the connection should just work, and most of these optional listen events give status you may only want to use during development and testing. + +Status events include a `transport` property that identifies which transport the event applies to. `CBLMultipeerReplicatorStatus` events are delivered per enabled transport and also as an aggregated status (where `transport` is `nil`) representing the overall replicator state. + +Event types include the following: + +==== Multipeer Replicator Status + +.Multipeer Replicator Status Listener +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-status-listener", indent=0] +---- + +==== Peer Discovery Status + +.Peer Discovery Status Listener +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-peer-discovery-listener", indent=0] +---- + +==== Peer's Replicator Status + +.Peer's Replicator Status Listener +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-replicator-status-listener", indent=0] +---- + +==== Peer's Document Replication + +.Peer's Document Replication Listener +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-document-replication-listener", indent=0] +---- + + +== Peer Info + +=== Peer Identifier + +A unique `peerID`, which is a digest of the peer's identity certificate, identifies each peer. +You can get your `peerID` from the `peerID` property of the `CBLMultipeerReplicator`. + + +.Getting peer ID +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-peer-id", indent=0] +---- + +=== Neighbor Peers + +You can get a list of current online peers' identifiers from the `CBLMultipeerReplicator` using the `neighborPeers` property. + +.Getting neighbor peers +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-neighbor-peers", indent=0] +---- + +=== Peer Info + +The `CBLPeerInfo` object provides information about a peer, including its identifier, certificate, online status, replicator status, neighbor peers, the transports on which the peer was discovered, and the transport currently used for replication. + +.Getting peer info +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-peer-info", indent=0] +---- + + +== Logging + +`CBLLogDomain` sets up the logging of: + +. Peer discovery log messages +. Multipeer replication and mesh network management log messages + +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-logdomain", indent=0] +---- + + +== API Reference + +You can find https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-ios}{empty}/couchbase-lite-objc[Objective-C API References] here. \ No newline at end of file diff --git a/modules/objc/pages/p2psync-websocket.adoc b/modules/objc/pages/p2psync-websocket.adoc index c9cdc01c2..42452f477 100644 --- a/modules/objc/pages/p2psync-websocket.adoc +++ b/modules/objc/pages/p2psync-websocket.adoc @@ -1,4 +1,3 @@ - = Data Sync Peer-to-Peer :page-aliases: learn/objc-p2psync-websocket.adoc ifdef::show_edition[:page-edition: Enterprise Edition] @@ -20,6 +19,21 @@ Related Content -- https://docs.couchbase.com/mobile/{major}.{minor}.{maintenanc -- +[TIP] +.Multipeer P2P Replicator +==== +xref:p2psync-multipeer.adoc[Multipeer P2P Replicator] is available for Objective-C, offering: + +* Auto-discovery over Wi-Fi and, from CBL 4.1, Bluetooth Low Energy +* Automatic transport switching between Wi-Fi and Bluetooth when both are enabled +* Lightweight and low-maintenance configuration +* Dynamic mesh topology for optimal peer connectivity +* Secure communication via TLS and certificate-based authentication + +For many use cases, this will be quicker to develop for than Active-Passive peer-to-peer sync. +==== + + [#introduction] == Introduction // tag::introduction-full[] @@ -369,7 +383,7 @@ Please check this document for more info: https://source.android.com/security/ke -- -MacOS / iOS:: +MacOS / iOS:: + -- .Secure storage details @@ -524,11 +538,7 @@ https://blog.couchbase.com/[Blog] | https://docs.couchbase.com/tutorials/[Tutorials] . -xref:tutorials:cbl-p2p-sync-websockets:swift/cbl-p2p-sync-websockets.adoc[Getting Started with Peer-to-Peer Synchronization] - ++++ -++++ - - +++++ \ No newline at end of file From 66461a0e967a878900fb03f63abdb0a44c5c8f74 Mon Sep 17 00:00:00 2001 From: Fortune Ikechi Date: Mon, 27 Apr 2026 16:33:18 +0100 Subject: [PATCH 03/12] update code using api reference document --- .../codesnippets/MultipeerExamples.kt | 1 + .../code_snippets/MultipeerReplicator.m | 174 +++++++++++++----- .../code_snippets/MultipeerReplicator.swift | 159 +++++++++++----- 3 files changed, 236 insertions(+), 98 deletions(-) diff --git a/modules/android/examples/kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt b/modules/android/examples/kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt index 9dc02dcfd..ac080ed73 100644 --- a/modules/android/examples/kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt +++ b/modules/android/examples/kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt @@ -210,6 +210,7 @@ class MultipeerExamples { return config } + fun createMultipeerReplicator() : MultipeerReplicator { val config = createConfig() diff --git a/modules/objc/examples/code_snippets/MultipeerReplicator.m b/modules/objc/examples/code_snippets/MultipeerReplicator.m index 9a61856c3..e39f2468a 100644 --- a/modules/objc/examples/code_snippets/MultipeerReplicator.m +++ b/modules/objc/examples/code_snippets/MultipeerReplicator.m @@ -185,71 +185,106 @@ - (CBLMultipeerReplicatorConfiguration *)createConfig { return config; } -- (CBLMultipeerReplicator *)createMultipeerReplicator { - CBLMultipeerReplicatorConfiguration *config = [self createConfig]; - NSError *error = nil; - // tag::multipeer-replicator - CBLMultipeerReplicator *replicator = [[CBLMultipeerReplicator alloc] initWithConfig:config error:&error]; - // end::multipeer-replicator - return replicator; +- (CBLMultipeerReplicatorConfiguration *)createConfigTransportsDefault { + CBLTLSIdentity *identity = [self createCASignedIdentity]; + id authenticator = [self authenticatorWithRootCerts]; + NSArray *collections = [self collectionConfig]; + + // tag::multipeer-config-transports-default[] + // Wi-Fi is the default transport. No additional configuration is required. + CBLMultipeerReplicatorConfiguration *config = + [[CBLMultipeerReplicatorConfiguration alloc] initWithPeerGroupID:@"com.myapp" + identity:identity + authenticator:authenticator + collections:collections]; + // config.transports defaults to kCBLMultipeerTransportWifi + // end::multipeer-config-transports-default[] + return config; } -- (void)startReplicator { - CBLMultipeerReplicator *replicator = [self createMultipeerReplicator]; - // tag::multipeer-replicator-start - [replicator start]; - // end::multipeer-replicator-start +- (CBLMultipeerReplicatorConfiguration *)createConfigTransportsBoth { + CBLTLSIdentity *identity = [self createCASignedIdentity]; + id authenticator = [self authenticatorWithRootCerts]; + NSArray *collections = [self collectionConfig]; + + // tag::multipeer-config-transports-both[] + CBLMultipeerReplicatorConfiguration *config = + [[CBLMultipeerReplicatorConfiguration alloc] initWithPeerGroupID:@"com.myapp" + identity:identity + authenticator:authenticator + collections:collections]; + config.transports = kCBLMultipeerTransportWifi | kCBLMultipeerTransportBluetooth; + // end::multipeer-config-transports-both[] + return config; } -- (void)stopReplicator { - CBLMultipeerReplicator *replicator = [self createMultipeerReplicator]; - // tag::multipeer-replicator-stop - [replicator stop]; - // end::multipeer-replicator-stop +- (CBLMultipeerReplicatorConfiguration *)createConfigTransportsBluetoothOnly { + CBLTLSIdentity *identity = [self createCASignedIdentity]; + id authenticator = [self authenticatorWithRootCerts]; + NSArray *collections = [self collectionConfig]; + + // tag::multipeer-config-transports-bluetooth-only[] + CBLMultipeerReplicatorConfiguration *config = + [[CBLMultipeerReplicatorConfiguration alloc] initWithPeerGroupID:@"com.myapp" + identity:identity + authenticator:authenticator + collections:collections]; + config.transports = kCBLMultipeerTransportBluetooth; + // end::multipeer-config-transports-bluetooth-only[] + return config; } - (void)statusListener { CBLMultipeerReplicator *replicator = [self createMultipeerReplicator]; - // tag::multipeer-status-listener + // tag::multipeer-status-listener[] [replicator addStatusListenerWithQueue:nil listener:^(CBLMultipeerReplicatorStatus *status) { + // transport is nil for the aggregated overall status; + // non-nil for a per-transport status update. + NSString *transport = status.transport == nil ? @"all" + : (status.transport.unsignedIntegerValue == kCBLMultipeerTransportWifi ? @"wifi" : @"bluetooth"); NSString *state = status.active ? @"active" : @"inactive"; NSString *err = status.error ? status.error.localizedDescription : @"none"; - NSLog(@"Multipeer Replicator Status: %@, Error: %@", state, err); + NSLog(@"Multipeer Replicator [%@]: %@, Error: %@", transport, state, err); }]; - // end::multipeer-status-listener + // end::multipeer-status-listener[] } - (void)peerDiscoveryListener { CBLMultipeerReplicator *replicator = [self createMultipeerReplicator]; - // tag::multipeer-peer-discovery-listener + // tag::multipeer-peer-discovery-listener[] [replicator addPeerDiscoveryStatusListenerWithQueue:nil listener:^(CBLPeerDiscoveryStatus *status) { NSString *online = status.online ? @"online" : @"offline"; - NSLog(@"Peer Discovery Status - Peer ID: %@, Status: %@", status.peerID, online); + NSString *transport = (status.transport == kCBLMultipeerTransportWifi) ? @"wifi" : @"bluetooth"; + NSLog(@"Peer Discovery Status - Peer ID: %@, Transport: %@, Status: %@", + status.peerID, transport, online); }]; - // end::multipeer-peer-discovery-listener + // end::multipeer-peer-discovery-listener[] } - (void)peerReplicatorStatus { CBLMultipeerReplicator *replicator = [self createMultipeerReplicator]; - // tag::multipeer-replicator-status-listener + // tag::multipeer-replicator-status-listener[] NSArray *activities = @[ @"stopped", @"offline", @"connecting", @"idle", @"busy" ]; [replicator addPeerReplicatorStatusListenerWithQueue:nil listener:^(CBLPeerReplicatorStatus *replStatus) { NSString *direction = replStatus.outgoing ? @"outgoing" : @"incoming"; NSString *activity = activities[replStatus.status.activity]; + NSString *transport = (replStatus.transport == kCBLMultipeerTransportWifi) ? @"wifi" : @"bluetooth"; NSString *error = replStatus.status.error ? replStatus.status.error.localizedDescription : @"none"; NSLog(@"Peer Replicator Status - " - "Peer ID: %@, Direction: %@, Activity: %@, Error: %@", - replStatus.peerID, direction, activity, error); + "Peer ID: %@, Transport: %@, Direction: %@, Activity: %@, Error: %@", + replStatus.peerID, transport, direction, activity, error); }]; - // end::multipeer-replicator-status-listener + // end::multipeer-replicator-status-listener[] } - (void)peerDocumentReplication { CBLMultipeerReplicator *replicator = [self createMultipeerReplicator]; - // tag::multipeer-document-replication-listener + // tag::multipeer-document-replication-listener[] [replicator addPeerDocumentReplicationListenerWithQueue:nil listener:^(CBLPeerDocumentReplication *docRepl) { NSString *direction = docRepl.isPush ? @"Push" : @"Pull"; - NSLog(@"Peer Document Replication - Peer ID: %@, Direction: %@", docRepl.peerID, direction); + NSString *transport = (docRepl.transport == kCBLMultipeerTransportWifi) ? @"wifi" : @"bluetooth"; + NSLog(@"Peer Document Replication - Peer ID: %@, Transport: %@, Direction: %@", + docRepl.peerID, transport, direction); for (CBLReplicatedDocument *doc in docRepl.documents) { NSString *error = doc.error ? doc.error.localizedDescription : @"none"; NSString *collection = [NSString stringWithFormat:@"%@.%@", doc.scope, doc.collection]; @@ -257,35 +292,32 @@ - (void)peerDocumentReplication { collection, doc.id, (unsigned long)doc.flags, error); } }]; - // end::multipeer-document-replication-listener -} - -- (void)peerID { - CBLMultipeerReplicator *replicator = [self createMultipeerReplicator]; - // tag::multipeer-peer-id - CBLPeerID *peerID = replicator.peerID; - NSLog(@"Peer ID: %@", peerID); - // end::multipeer-peer-id -} - -- (void)neighborPeers { - CBLMultipeerReplicator *replicator = [self createMultipeerReplicator]; - // tag::multipeer-neighbor-peers - NSLog(@"Neighbor Peers:"); - for (CBLPeerID *peerID in replicator.neighborPeers) { - NSLog(@" %@", peerID); - } - // end::multipeer-neighbor-peers + // end::multipeer-document-replication-listener[] } - (void)peerInfo { CBLMultipeerReplicator *replicator = [self createMultipeerReplicator]; - // tag::multipeer-peer-info + // tag::multipeer-peer-info[] NSArray *activities = @[ @"stopped", @"offline", @"connecting", @"idle", @"busy" ]; void (^printPeerInfo)(CBLPeerInfo *) = ^(CBLPeerInfo *info) { NSLog(@"Peer ID: %@", info.peerID); NSLog(@" Status: %@", info.online ? @"online" : @"offline"); + + // transports: the set of transports on which this peer was discovered. + NSMutableArray *transportNames = [NSMutableArray array]; + if (info.transports & kCBLMultipeerTransportWifi) [transportNames addObject:@"wifi"]; + if (info.transports & kCBLMultipeerTransportBluetooth) [transportNames addObject:@"bluetooth"]; + NSLog(@" Discovered on: %@", [transportNames componentsJoinedByString:@", "]); + + // replicatorTransport: the transport currently used for replication. + // The value is kCBLMultipeerTransportWifi or kCBLMultipeerTransportBluetooth, + // or 0 if replication is not active. + NSString *replicatorTransport = (info.replicatorTransport == kCBLMultipeerTransportWifi) ? @"wifi" + : (info.replicatorTransport == kCBLMultipeerTransportBluetooth) ? @"bluetooth" + : @"none"; + NSLog(@" Replicating on: %@", replicatorTransport); + NSLog(@" Neighbor Peers:"); for (CBLPeerID *peerID in info.neighborPeers) { NSLog(@" %@", peerID); @@ -303,7 +335,49 @@ - (void)peerInfo { printPeerInfo(peerInfo); } } - // end::multipeer-peer-info + // end::multipeer-peer-info[] +} + + +- (CBLMultipeerReplicator *)createMultipeerReplicator { + CBLMultipeerReplicatorConfiguration *config = [self createConfig]; + NSError *error = nil; + // tag::multipeer-replicator + CBLMultipeerReplicator *replicator = [[CBLMultipeerReplicator alloc] initWithConfig:config error:&error]; + // end::multipeer-replicator + return replicator; +} + +- (void)startReplicator { + CBLMultipeerReplicator *replicator = [self createMultipeerReplicator]; + // tag::multipeer-replicator-start + [replicator start]; + // end::multipeer-replicator-start +} + +- (void)stopReplicator { + CBLMultipeerReplicator *replicator = [self createMultipeerReplicator]; + // tag::multipeer-replicator-stop + [replicator stop]; + // end::multipeer-replicator-stop +} + +- (void)peerID { + CBLMultipeerReplicator *replicator = [self createMultipeerReplicator]; + // tag::multipeer-peer-id + CBLPeerID *peerID = replicator.peerID; + NSLog(@"Peer ID: %@", peerID); + // end::multipeer-peer-id +} + +- (void)neighborPeers { + CBLMultipeerReplicator *replicator = [self createMultipeerReplicator]; + // tag::multipeer-neighbor-peers + NSLog(@"Neighbor Peers:"); + for (CBLPeerID *peerID in replicator.neighborPeers) { + NSLog(@" %@", peerID); + } + // end::multipeer-neighbor-peers } @end diff --git a/modules/swift/examples/code_snippets/MultipeerReplicator.swift b/modules/swift/examples/code_snippets/MultipeerReplicator.swift index 651ba8752..a7ce26fe4 100644 --- a/modules/swift/examples/code_snippets/MultipeerReplicator.swift +++ b/modules/swift/examples/code_snippets/MultipeerReplicator.swift @@ -68,7 +68,7 @@ class MultipeerReplicatorSnippets { // Define certificate attributes and expiration date. let attrs: [String: String] = [certAttrCommonName: "MyApp"] let expiration = Calendar.current.date(byAdding: .year, value: 2, to: Date())! - + // Create and store a new self-signed identity in the keychain with a persistent label. identity = try TLSIdentity.createIdentity( for: [.clientAuth, .serverAuth], @@ -79,7 +79,7 @@ class MultipeerReplicatorSnippets { // end::multipeer-selfsigned-tlsidentity[] return identity! } - + func createCASignedIdentity() throws -> TLSIdentity { // tag::multipeer-tlsidentity[] let persistentLabel = "com.myapp.identity" @@ -102,7 +102,7 @@ class MultipeerReplicatorSnippets { // Get issuer's private key and certificate data (DER format) for signing the identity's certificate. let caKey = try getIssuerPrivateKeyData() let caCert = try getIssuerCertificateData() - + // Create and store a new identity signed with the issuer in the keychain with a persistent label. identity = try TLSIdentity.createSignedIdentityInsecure( for: [.clientAuth, .serverAuth], @@ -158,52 +158,81 @@ class MultipeerReplicatorSnippets { return config } - func createMultipeerReplicator() throws -> MultipeerReplicator { - let config = try createConfig() - // tag::multipeer-replicator[] - let replicator = try MultipeerReplicator(config: config) - // end::multipeer-replicator[] - return replicator + func createConfigTransportsDefault() throws -> MultipeerReplicatorConfiguration { + let identity = try createCASignedIdentity() + let authenticator = try authenticatorWithRootCerts() + let collections = try collectionConfig() + + // tag::multipeer-config-transports-default[] + // Wi-Fi is the default transport. No additional configuration is required. + let config = MultipeerReplicatorConfiguration( + peerGroupID: "com.myapp", + identity: identity, + authenticator: authenticator, + collections: collections) + // config.transports defaults to [.wifi] + // end::multipeer-config-transports-default[] + return config } - func startReplicator() throws { - let replicator = try createMultipeerReplicator() - // tag::multipeer-replicator-start[] - replicator.start() - // end::multipeer-replicator-start[] + func createConfigTransportsBoth() throws -> MultipeerReplicatorConfiguration { + let identity = try createCASignedIdentity() + let authenticator = try authenticatorWithRootCerts() + let collections = try collectionConfig() + + // tag::multipeer-config-transports-both[] + var config = MultipeerReplicatorConfiguration( + peerGroupID: "com.myapp", + identity: identity, + authenticator: authenticator, + collections: collections) + config.transports = [.wifi, .bluetooth] + // end::multipeer-config-transports-both[] + return config } - func stopReplicator() throws { - let replicator = try createMultipeerReplicator() - // tag::multipeer-replicator-stop[] - replicator.stop() - // end::multipeer-replicator-stop[] + func createConfigTransportsBluetoothOnly() throws -> MultipeerReplicatorConfiguration { + let identity = try createCASignedIdentity() + let authenticator = try authenticatorWithRootCerts() + let collections = try collectionConfig() + + // tag::multipeer-config-transports-bluetooth-only[] + var config = MultipeerReplicatorConfiguration( + peerGroupID: "com.myapp", + identity: identity, + authenticator: authenticator, + collections: collections) + config.transports = [.bluetooth] + // end::multipeer-config-transports-bluetooth-only[] + return config } func statusListener() throws { let replicator = try createMultipeerReplicator() // tag::multipeer-status-listener[] let token = replicator.addStatusListener { status in + // transport is nil for the aggregated overall status; + // non-nil for a per-transport status update. + let transport = status.transport.map { $0 == .wifi ? "wifi" : "bluetooth" } ?? "all" let state = status.active ? "active" : "inactive" let error = status.error?.localizedDescription ?? "none" - print("Multipeer Replicator: \(state), Error: \(error)") + print("Multipeer Replicator [\(transport)]: \(state), Error: \(error)") } // end::multipeer-status-listener[] - - // to hide the warning print(token) } + func peerDiscoveryListener() throws { let replicator = try createMultipeerReplicator() // tag::multipeer-peer-discovery-listener[] let token = replicator.addPeerDiscoveryStatusListener { status in let online = status.online ? "online" : "offline" - print("Peer Discovery Status - Peer ID: \(status.peerID), Status: \(online)") + let transport = status.transport == .wifi ? "wifi" : "bluetooth" + print("Peer Discovery Status - Peer ID: \(status.peerID), " + + "Transport: \(transport), Status: \(online)") } // end::multipeer-peer-discovery-listener[] - - // to hide the warning print(token) } @@ -214,15 +243,15 @@ class MultipeerReplicatorSnippets { let token = replicator.addPeerReplicatorStatusListener { replStatus in let direction = replStatus.outgoing ? "outgoing" : "incoming" let activity = activities[Int(replStatus.status.activity.rawValue)] + let transport = replStatus.transport == .wifi ? "wifi" : "bluetooth" let error = replStatus.status.error?.localizedDescription ?? "none" print("Peer Replicator Status - Peer ID: \(replStatus.peerID), " + + "Transport: \(transport), " + "Direction: \(direction), " + "Activity: \(activity), " + "Error: \(error)") } // end::multipeer-replicator-status-listener[] - - // to hide the warning print(token) } @@ -231,7 +260,9 @@ class MultipeerReplicatorSnippets { // tag::multipeer-document-replication-listener[] let token = replicator.addPeerDocumentReplicationListener { docRepl in let direction = docRepl.isPush ? "Push" : "Pull" - print("Peer Document Replication - Peer ID: \(docRepl.peerID), Direction: \(direction)") + let transport = docRepl.transport == .wifi ? "wifi" : "bluetooth" + print("Peer Document Replication - Peer ID: \(docRepl.peerID), " + + "Transport: \(transport), Direction: \(direction)") docRepl.documents.forEach { doc in let error = doc.error?.localizedDescription ?? "none" let collection = "\(doc.scope).\(doc.collection)" @@ -242,29 +273,9 @@ class MultipeerReplicatorSnippets { } } // end::multipeer-document-replication-listener[] - - // to hide the warning print(token) } - func peerID() throws { - let replicator = try createMultipeerReplicator() - // tag::multipeer-peer-id[] - let peerID = replicator.peerID - print("Peer ID: \(peerID)") - // end::multipeer-peer-id[] - } - - func neighborPeers() throws { - let replicator = try createMultipeerReplicator() - // tag::multipeer-neighbor-peers[] - print("Neighbor Peers:") - replicator.neighborPeers.forEach { peerID in - print(" \(peerID)") - } - // end::multipeer-neighbor-peers[] - } - func peerInfo() throws { let replicator = try createMultipeerReplicator() // tag::multipeer-peer-info[] @@ -273,6 +284,16 @@ class MultipeerReplicatorSnippets { let printPeerInfo: (PeerInfo) -> Void = { info in print("Peer ID: \(info.peerID)") print(" Status: \(info.online ? "online" : "offline")") + + // transports: the set of transports on which this peer was discovered. + let transports = info.transports.map { $0 == .wifi ? "wifi" : "bluetooth" }.joined(separator: ", ") + print(" Discovered on: \(transports)") + + // replicatorTransport: the transport currently used for replication, + // or nil if replication is not active. + let replicatorTransport = info.replicatorTransport.map { $0 == .wifi ? "wifi" : "bluetooth" } ?? "none" + print(" Replicating on: \(replicatorTransport)") + print(" Neighbor Peers:") info.neighborPeers.forEach { peerID in print(" \(peerID)") @@ -289,9 +310,51 @@ class MultipeerReplicatorSnippets { printPeerInfo(peerInfo) } } + + } // end::multipeer-peer-info[] + + func createMultipeerReplicator() throws -> MultipeerReplicator { + let config = try createConfig() + // tag::multipeer-replicator[] + let replicator = try MultipeerReplicator(config: config) + // end::multipeer-replicator[] + return replicator } + func startReplicator() throws { + let replicator = try createMultipeerReplicator() + // tag::multipeer-replicator-start[] + replicator.start() + // end::multipeer-replicator-start[] + } + + func stopReplicator() throws { + let replicator = try createMultipeerReplicator() + // tag::multipeer-replicator-stop[] + replicator.stop() + // end::multipeer-replicator-stop[] + } + + func peerID() throws { + let replicator = try createMultipeerReplicator() + // tag::multipeer-peer-id[] + let peerID = replicator.peerID + print("Peer ID: \(peerID)") + // end::multipeer-peer-id[] + } + + func neighborPeers() throws { + let replicator = try createMultipeerReplicator() + // tag::multipeer-neighbor-peers[] + print("Neighbor Peers:") + replicator.neighborPeers.forEach { peerID in + print(" \(peerID)") + } + // end::multipeer-neighbor-peers[] + } + + func logging() throws { // tag::multipeer-logdomain[] // Enable verbose console logging for multipeer replicator-related domains only. From 14cd36865f53e61cc8f679e78f031a10a547599f Mon Sep 17 00:00:00 2001 From: Fortune Ikechi Date: Tue, 28 Apr 2026 15:31:24 +0100 Subject: [PATCH 04/12] update texts based on feedback --- modules/android/pages/p2psync-multipeer.adoc | 11 +++++++---- .../objc/examples/code_snippets/MultipeerReplicator.m | 10 +++++++--- modules/objc/pages/p2psync-multipeer.adoc | 8 ++++++-- modules/swift/pages/p2psync-multipeer.adoc | 5 +++-- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/modules/android/pages/p2psync-multipeer.adoc b/modules/android/pages/p2psync-multipeer.adoc index 9e7386145..6c36648b9 100644 --- a/modules/android/pages/p2psync-multipeer.adoc +++ b/modules/android/pages/p2psync-multipeer.adoc @@ -64,7 +64,10 @@ This self-organizing approach ensures reliable data synchronization even in chal == Prerequisites -The Multipeer Replicator supports two transports for peer discovery and replication: Wi-Fi and Bluetooth Low Energy (BLE). Wi-Fi is enabled by default. Bluetooth is optional and you enable it through the replicator configuration. See <>. +The Multipeer Replicator supports two transports for peer discovery and replication: Wi-Fi and Bluetooth Low Energy (BLE). +Wi-Fi is enabled by default. +The enabled transports are configured through the replicator configuration. +See <>. === Transport Support @@ -88,9 +91,9 @@ The Multipeer Replicator supports two transports for peer discovery and replicat === Supported Platforms -For Wi-Fi transport, CBL supports Android API 24 and higher. - -For Bluetooth transport, CBL supports Android API 29 and higher. On API 29 and 30, Bluetooth uses the legacy `BLUETOOTH`, `BLUETOOTH_ADMIN`, and `ACCESS_FINE_LOCATION` permissions. On API 31 and higher, Bluetooth uses the runtime permissions `BLUETOOTH_SCAN`, `BLUETOOTH_ADVERTISE`, and `BLUETOOTH_CONNECT`. +For Bluetooth transport, CBL supports Android API 29 and higher. +On API 29 and 30, Bluetooth requires the legacy `BLUETOOTH`, `BLUETOOTH_ADMIN`, and `ACCESS_FINE_LOCATION` permissions. +On API 31 and higher, Bluetooth requires the runtime permissions `BLUETOOTH_SCAN`, `BLUETOOTH_ADVERTISE`, and `BLUETOOTH_CONNECT`. See xref:android:supported-os.adoc[Supported Platforms] for the full platform support matrix. diff --git a/modules/objc/examples/code_snippets/MultipeerReplicator.m b/modules/objc/examples/code_snippets/MultipeerReplicator.m index e39f2468a..e71b3ddbf 100644 --- a/modules/objc/examples/code_snippets/MultipeerReplicator.m +++ b/modules/objc/examples/code_snippets/MultipeerReplicator.m @@ -306,9 +306,13 @@ - (void)peerInfo { // transports: the set of transports on which this peer was discovered. NSMutableArray *transportNames = [NSMutableArray array]; - if (info.transports & kCBLMultipeerTransportWifi) [transportNames addObject:@"wifi"]; - if (info.transports & kCBLMultipeerTransportBluetooth) [transportNames addObject:@"bluetooth"]; - NSLog(@" Discovered on: %@", [transportNames componentsJoinedByString:@", "]); + if ((info.transports & kCBLMultipeerTransportWifi) != 0) { + [transportNames addObject:@"wifi"]; + } + + if ((info.transports & kCBLMultipeerTransportBluetooth) != 0) { + [transportNames addObject:@"bluetooth"]; + } // replicatorTransport: the transport currently used for replication. // The value is kCBLMultipeerTransportWifi or kCBLMultipeerTransportBluetooth, diff --git a/modules/objc/pages/p2psync-multipeer.adoc b/modules/objc/pages/p2psync-multipeer.adoc index 76ee9836f..a0757c24f 100644 --- a/modules/objc/pages/p2psync-multipeer.adoc +++ b/modules/objc/pages/p2psync-multipeer.adoc @@ -21,7 +21,8 @@ The dynamic mesh topology gives optimal peer connectivity and the lightweight an == Overview To maintain optimal connectivity, efficient data transport, and balanced workloads, the Multipeer Replicator forms a dynamic mesh network among peers in the same group. -The mesh network provides resilience through multiple communication pathways. If one connection fails, data can flow through alternative routes. +The mesh network provides resilience through multiple communication pathways. +If one connection fails, data can flow through alternative routes. It avoids redundant direct connections, evenly distributes connections across peers, and optimizes communication paths through intelligent routing. The mesh network continuously adapts as peers join or leave, automatically healing itself by establishing new connections and rerouting data flow to maintain network integrity. @@ -31,7 +32,10 @@ This self-organizing approach ensures reliable data synchronization even in chal == Prerequisites -The Multipeer Replicator supports two transports for peer discovery and replication: Wi-Fi and Bluetooth Low Energy (BLE). Wi-Fi is enabled by default. Bluetooth is optional and you enable it through the replicator configuration. See <>. +The Multipeer Replicator supports two transports for peer discovery and replication: Wi-Fi and Bluetooth Low Energy (BLE). +Wi-Fi is enabled by default. +The enabled transports are configured through the replicator configuration. +See <>. === Transport Support diff --git a/modules/swift/pages/p2psync-multipeer.adoc b/modules/swift/pages/p2psync-multipeer.adoc index 003b0dd0b..49ebfc320 100644 --- a/modules/swift/pages/p2psync-multipeer.adoc +++ b/modules/swift/pages/p2psync-multipeer.adoc @@ -68,8 +68,9 @@ This self-organizing approach ensures reliable data synchronization even in chal == Prerequisites -The Multipeer Replicator supports two transports for peer discovery and replication: Wi-Fi and Bluetooth Low Energy (BLE). Wi-Fi is enabled by default. -Bluetooth is optional and you enable it through the replicator configuration. +The Multipeer Replicator supports two transports for peer discovery and replication: Wi-Fi and Bluetooth Low Energy (BLE). +Wi-Fi is enabled by default. +The enabled transports are configured through the replicator configuration. See <>. === Transport Support From b3bb09d41b6a1dcaac794eed2d7b071db7ff08d3 Mon Sep 17 00:00:00 2001 From: Pasin Suriyentrakorn Date: Wed, 1 Apr 2026 09:04:28 -0700 Subject: [PATCH 05/12] Fix Jenkins PR Validation (#1087) * iOS : - Fixed and simplify script to download the right CBL and VS binary. - Fixed one error in code snippet. * C : - Applied the same method as iOS get the lastest CBL version. - Removed obsolete logging code snippet as the API has been changed in 4.0 * Android: - Updated AGP from 8.0.2 to 8.13.2 to fix JDK 21 incompatibility issue. - Update Android script to get CBL and VS version based on isReleased flag. --- jenkins/android_build.sh | 33 +++++++++- jenkins/c_build.sh | 32 +++++++-- jenkins/ios.sh | 66 ++++++++++--------- modules/android/examples/build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../examples/java_snippets/app/build.gradle | 8 +-- modules/c/examples/code_snippets/main.cpp | 25 ------- .../examples/code_snippets/SampleCodeTest.m | 5 +- 8 files changed, 99 insertions(+), 74 deletions(-) diff --git a/jenkins/android_build.sh b/jenkins/android_build.sh index 0b1e1a13a..fea9fbf2b 100755 --- a/jenkins/android_build.sh +++ b/jenkins/android_build.sh @@ -70,8 +70,35 @@ fi CBL_URL="http://proget.build.couchbase.com:8080/api/get_version?product=couchbase-lite-android&version=${CBL_VERSION}" VS_URL="http://proget.build.couchbase.com:8080/api/get_version?product=couchbase-lite-android-vector-search&version=${VS_VERSION}" -CBL_BUILD=$(curl -s $CBL_URL | $JQ -r '.BuildNumber') -VS_BUILD=$(curl -s $VS_URL | $JQ -r '.BuildNumber') +CBL_RESPONSE=$(curl -s $CBL_URL) +CBL_IS_RELEASE=$(echo -n "$CBL_RESPONSE" | $JQ -r '.IsRelease') +CBL_BUILD=$(echo -n "$CBL_RESPONSE" | $JQ -r '.BuildNumber') + +if [ "${CBL_BUILD}" == "" ] || [ "${CBL_BUILD}" == "null" ]; then + echo "No latest successful build found for CBL v${CBL_VERSION}" + exit 3 +fi + +VS_RESPONSE=$(curl -s $VS_URL) +VS_IS_RELEASE=$(echo -n "$VS_RESPONSE" | $JQ -r '.IsRelease') +VS_BUILD=$(echo -n "$VS_RESPONSE" | $JQ -r '.BuildNumber') + +if [ "${VS_BUILD}" == "" ] || [ "${VS_BUILD}" == "null" ]; then + echo "No latest successful build found for VS v${VS_VERSION}" + exit 3 +fi + +if [ "${CBL_IS_RELEASE}" == "true" ]; then + CBL_VERSION_ARG="${CBL_VERSION}" +else + CBL_VERSION_ARG="${CBL_VERSION}-${CBL_BUILD}" +fi + +if [ "${VS_IS_RELEASE}" == "true" ]; then + VS_VERSION_ARG="${VS_VERSION}" +else + VS_VERSION_ARG="${VS_VERSION}-${VS_BUILD}" +fi pushd $ANDROID_DIR/examples/ -./gradlew assembleDebug -PcblVersion=$CBL_VERSION-$CBL_BUILD -PextVersion=$VS_VERSION-$VS_BUILD \ No newline at end of file +./gradlew assembleDebug -PcblVersion=${CBL_VERSION_ARG} -PextVersion=${VS_VERSION_ARG} \ No newline at end of file diff --git a/jenkins/c_build.sh b/jenkins/c_build.sh index 2ae6755a5..5adecd105 100755 --- a/jenkins/c_build.sh +++ b/jenkins/c_build.sh @@ -2,23 +2,41 @@ if [[ "$#" -ne 1 ]]; then echo "This script requires a version argument" + exit 1 fi -THIS_DIR=$( dirname -- $(realpath "$0"); ) -version="$1" +THIS_DIR=$( dirname -- $(realpath "$0") ) +CBL_VERSION="$1" pushd "$THIS_DIR/../modules/c/examples/code_snippets" -build_num=$(curl -s http://dbapi.build.couchbase.com:8000/v1/products/couchbase-lite-c/releases/$version/versions/$version/builds?filter=last_complete | jq .build_num | bc) +RESPONSE=$(curl -s "http://proget.build.couchbase.com:8080/api/get_version?product=couchbase-lite-c&version=${CBL_VERSION}") +CBL_IS_RELEASE=$(echo -n "$RESPONSE" | jq .IsRelease) +CBL_BUILD_NO=$(echo -n "$RESPONSE" | jq .BuildNumber) + +if [ "${CBL_BUILD_NO}" == "" ] || [ "${CBL_BUILD_NO}" == "null" ]; then + echo "No latest successful build found for CBL v${CBL_VERSION}" + exit 3 +fi + +if [ "${CBL_IS_RELEASE}" == "true" ]; then + PACKAGE_NAME="couchbase-lite-c-enterprise-${CBL_VERSION}-linux-x86_64.tar.gz" + DOWNLOAD_URL="https://latestbuilds.service.couchbase.com/builds/releases/mobile/couchbase-lite-c/${CBL_VERSION}/${PACKAGE_NAME}" +else + PACKAGE_NAME="couchbase-lite-c-enterprise-${CBL_VERSION}-${CBL_BUILD_NO}-linux-x86_64.tar.gz" + DOWNLOAD_URL="https://latestbuilds.service.couchbase.com/builds/latestbuilds/couchbase-lite-c/${CBL_VERSION}/${CBL_BUILD_NO}/${PACKAGE_NAME}" +fi + +rm -rf downloaded mkdir -p downloaded pushd downloaded DOWNLOAD_DIR=$(pwd) -wget http://latestbuilds.service.couchbase.com/builds/latestbuilds/couchbase-lite-c/$version/$build_num/couchbase-lite-c-enterprise-$version-$build_num-linux-x86_64.tar.gz -tar xf couchbase-lite-c-enterprise-$version-$build_num-linux-x86_64.tar.gz -rm couchbase-lite-c-enterprise-$version-$build_num-linux-x86_64.tar.gz +wget "${DOWNLOAD_URL}" +tar xf "${PACKAGE_NAME}" +rm "${PACKAGE_NAME}" popd mkdir -p build pushd build -cmake -DCMAKE_PREFIX_PATH="$DOWNLOAD_DIR/libcblite-$version" .. +cmake -DCMAKE_PREFIX_PATH="$DOWNLOAD_DIR/libcblite-${CBL_VERSION}" .. make -j12 diff --git a/jenkins/ios.sh b/jenkins/ios.sh index 0552ad90f..a49ad3848 100755 --- a/jenkins/ios.sh +++ b/jenkins/ios.sh @@ -3,20 +3,19 @@ CBL_VERSION=$1 VS_VERSION=$2 -dir=$( dirname -- $(realpath "$0"); ) - -# Get latest good CBL iOS EE build for given version -CBL_URL="http://proget.build.couchbase.com:8080/api/open_latestbuilds?product=couchbase-lite-ios&version=${cbl_version}" +if [ -z "${CBL_VERSION}" ] || [ -z "${VS_VERSION}" ]; then + echo "Usage: $0 " + exit 1 +fi -# Grab the redirect url -CBL_SOURCE_URL=$(curl -s -L -o /dev/null -w '%{url_effective}' "${CBL_URL}") +dir=$( dirname -- $(realpath "$0") ) CBL="http://proget.build.couchbase.com:8080/api/get_version?product=couchbase-lite-ios&version=${CBL_VERSION}" RESPONSE=$(curl -s $CBL) -CBL_IS_RELEASE=$(echo -n $RESPONSE | jq .IsRelease) -CBL_BUILD_NO=$(echo -n $RESPONSE | jq .BuildNumber) +CBL_IS_RELEASE=$(echo -n "$RESPONSE" | jq .IsRelease) +CBL_BUILD_NO=$(echo -n "$RESPONSE" | jq .BuildNumber) -if [ "${CBL_BUILD_NO}" == "" ] +if [ "${CBL_BUILD_NO}" == "" ] || [ "${CBL_BUILD_NO}" == "null" ] then echo "No latest successful build found for CBL v${CBL_VERSION}" exit 3 @@ -24,51 +23,54 @@ fi VS="http://proget.build.couchbase.com:8080/api/get_version?product=couchbase-lite-ios-vector-search&version=${VS_VERSION}&ee=true" RESPONSE=$(curl -s $VS) -VS_BUILD_NO=$(echo -n $RESPONSE | jq .BuildNumber) +VS_IS_RELEASE=$(echo -n "$RESPONSE" | jq .IsRelease) +VS_BUILD_NO=$(echo -n "$RESPONSE" | jq .BuildNumber) -if [ "${VS_BUILD_NO}" == "" ] +if [ "${VS_BUILD_NO}" == "" ] || [ "${VS_BUILD_NO}" == "null" ] then echo "No latest successful build found for VS v${VS_VERSION}" exit 3 fi +# Download VS extension once (platform-independent) +if [ "${VS_IS_RELEASE}" == "true" ]; then + VS_PACKAGE_NAME="couchbase-lite-vector-search-${VS_VERSION}-apple.zip" + VS_URL="https://latestbuilds.service.couchbase.com/builds/releases/mobile/couchbase-lite-vector-search/${VS_VERSION}/${VS_PACKAGE_NAME}" +else + VS_PACKAGE_NAME="couchbase-lite-vector-search-${VS_VERSION}-${VS_BUILD_NO}-apple.zip" + VS_URL="https://latestbuilds.service.couchbase.com/builds/latestbuilds/couchbase-lite-vector-search/${VS_VERSION}/${VS_BUILD_NO}/${VS_PACKAGE_NAME}" +fi + +VS_DOWNLOAD_DIR="${dir}/../vs_downloaded" +rm -rf "${VS_DOWNLOAD_DIR}" +mkdir -p "${VS_DOWNLOAD_DIR}" +wget -P "${VS_DOWNLOAD_DIR}" "${VS_URL}" + for PLATFORM in "objc" "swift" do echo $PLATFORM pushd "${dir}/../modules/${PLATFORM}/examples" # In case script fails mid-way, cleanup on start - if [ -d "downloaded" ]; then - rm -rf "downloaded" - fi + rm -rf "downloaded" mkdir -p downloaded pushd downloaded - # Get CBL - CBL_SOURCE_URL=$(curl -s -L -o /dev/null -w '%{url_effective}' "http://proget.build.couchbase.com:8080/api/open_latestbuilds?product=couchbase-lite-ios&version=${CBL_VERSION}") - if [ $CBL_IS_RELEASE == true ]; then + # Get CBL + if [ "${CBL_IS_RELEASE}" == "true" ]; then CBL_PACKAGE_NAME="couchbase-lite-${PLATFORM}_xc_enterprise_${CBL_VERSION}.zip" + CBL_URL="https://latestbuilds.service.couchbase.com/builds/releases/mobile/couchbase-lite-ios/${CBL_VERSION}/${CBL_PACKAGE_NAME}" else CBL_PACKAGE_NAME="couchbase-lite-${PLATFORM}_xc_enterprise_${CBL_VERSION}-${CBL_BUILD_NO}.zip" + CBL_URL="https://latestbuilds.service.couchbase.com/builds/latestbuilds/couchbase-lite-ios/${CBL_VERSION}/${CBL_BUILD_NO}/${CBL_PACKAGE_NAME}" fi - wget "$CBL_SOURCE_URL$CBL_PACKAGE_NAME" - unzip -o $CBL_PACKAGE_NAME -d "../Frameworks/" + wget "${CBL_URL}" + unzip -o "${CBL_PACKAGE_NAME}" -d "../Frameworks/" # Get VS extension - VS_SOURCE_URL=$(curl -s -L -o /dev/null -w '%{url_effective}' "http://proget.build.couchbase.com:8080/api/open_latestbuilds?product=couchbase-lite-ios-vector-search&version=${VS_VERSION}") - echo $VS_SOURCE_URL - VS_PACKAGE_NAME="couchbase-lite-vector-search-${VS_VERSION}-${VS_BUILD_NO}-apple.zip" - wget "$VS_SOURCE_URL$VS_PACKAGE_NAME" - unzip -o $VS_PACKAGE_NAME -d "../Frameworks/" - - # Check if download was successful - if [ $? -eq 0 ]; then - echo "Package downloaded successfully." - else - echo "Failed to download the package." - fi + unzip -o "${VS_DOWNLOAD_DIR}/${VS_PACKAGE_NAME}" -d "../Frameworks/" popd @@ -79,3 +81,5 @@ do popd done + +rm -rf "${VS_DOWNLOAD_DIR}" diff --git a/modules/android/examples/build.gradle b/modules/android/examples/build.gradle index 6ca80790f..3d0ec6451 100644 --- a/modules/android/examples/build.gradle +++ b/modules/android/examples/build.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.20" - classpath 'com.android.tools.build:gradle:8.0.2' + classpath 'com.android.tools.build:gradle:8.13.2' } } diff --git a/modules/android/examples/gradle/wrapper/gradle-wrapper.properties b/modules/android/examples/gradle/wrapper/gradle-wrapper.properties index a59520664..2733ed5dc 100644 --- a/modules/android/examples/gradle/wrapper/gradle-wrapper.properties +++ b/modules/android/examples/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/modules/android/examples/java_snippets/app/build.gradle b/modules/android/examples/java_snippets/app/build.gradle index d0c4c7a8d..8eb5f0c0b 100644 --- a/modules/android/examples/java_snippets/app/build.gradle +++ b/modules/android/examples/java_snippets/app/build.gradle @@ -33,10 +33,6 @@ android { targetCompatibility JavaVersion.VERSION_11 } - lintOptions { - disable 'UseSparseArrays' - abortOnError false - } sourceSets { main { @@ -46,6 +42,10 @@ android { ] } } + lint { + abortOnError false + disable 'UseSparseArrays' + } } repositories { diff --git a/modules/c/examples/code_snippets/main.cpp b/modules/c/examples/code_snippets/main.cpp index cb34670c8..c5da8611a 100644 --- a/modules/c/examples/code_snippets/main.cpp +++ b/modules/c/examples/code_snippets/main.cpp @@ -1688,10 +1688,6 @@ static void start_replication() { } static void console_log_sink() { - // tag::console-logging[] - CBLLog_SetConsoleLevel(kCBLLogVerbose); - // end::console-logging[] - // tag::new-console-logging[] CBLConsoleLogSink logSink {}; logSink.level = kCBLLogVerbose; @@ -1701,23 +1697,6 @@ static void console_log_sink() { } static void file_log_sink() { - // tag::file-logging[] - // NOTE: No error handling, for brevity (see getting started) - - // NOTE: You will need to use a platform appropriate method for finding - // a temporary directory - - CBLLogFileConfiguration config {}; // Don't bother zeroing, since we set all properties - config.level = kCBLLogInfo; - config.directory = FLSTR("/tmp/logs");; - config.maxRotateCount = 12; - config.maxSize = 1048576; - config.usePlaintext = false; - - CBLError err{}; - CBLLog_SetFileConfig(config, &err); - // end::file-logging[] - // tag::new-file-logging[] CBLFileLogSink logSink {}; logSink.level = kCBLLogVerbose; @@ -1742,10 +1721,6 @@ static void custom_log_sink_callback(CBLLogDomain domain, CBLLogLevel level, FLS // end::new-custom-logging[] static void enable_custom_log_sink() { - // tag::set-custom-logging[] - CBLLog_SetCallback(custom_log_callback); - // end::set-custom-logging[] - // tag::set-new-custom-logging[] CBLCustomLogSink logSink {}; logSink.level = kCBLLogVerbose; diff --git a/modules/objc/examples/code_snippets/SampleCodeTest.m b/modules/objc/examples/code_snippets/SampleCodeTest.m index 6b43de239..25a39f29f 100644 --- a/modules/objc/examples/code_snippets/SampleCodeTest.m +++ b/modules/objc/examples/code_snippets/SampleCodeTest.m @@ -683,11 +683,12 @@ - (void) dontTestCollectionOperatorIn { [CBLQueryExpression property:@"last"], [CBLQueryExpression property:@"username"]]; - [CBLQueryBuilder select:@[[CBLQuerySelectResult all]] + CBLQuery *query = [CBLQueryBuilder select:@[[CBLQuerySelectResult all]] from:[CBLQueryDataSource collection:self.collection] where:[[CBLQueryExpression string:@"Armani"] in:values]]; - NSLog(@"%@", query); // end::query-collection-operator-in[] + + NSLog(@"%@", query); } - (void) dontTestLikeOperator { From 9265ad0f01a2ac09587206f6db081c2a0c17493e Mon Sep 17 00:00:00 2001 From: Fortune Ikechi Date: Tue, 28 Apr 2026 16:03:22 +0100 Subject: [PATCH 06/12] update the version for jenkensilfe --- Jenkinsfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 542f8bcf4..7140207bd 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -9,25 +9,25 @@ pipeline { stage("Validate C#") { agent { label 's61113u16 (litecore)' } steps { - sh 'jenkins/dotnet_build.sh 4.0.0 2.0.0' + sh 'jenkins/dotnet_build.sh 4.1.0 2.0.0' } } stage("Validate C") { agent { label 's61113u16 (litecore)' } steps { - sh 'jenkins/c_build.sh 4.0.0' + sh 'jenkins/c_build.sh 4.1.0' } } stage("Validate iOS") { agent { label 'mobile-builder-ios-pull-request' } steps { - sh 'jenkins/ios.sh 4.0.0 2.0.0' + sh 'jenkins/ios.sh 4.1.0 2.0.0' } } stage("Validate Android") { agent { label 'cbl-android' } steps { - sh 'jenkins/android_build.sh 4.0.0 2.0.0' + sh 'jenkins/android_build.sh 4.1.0 2.0.0' } } } From 5d915250b2a4eed0f46543f8c9bfc52fb66f007f Mon Sep 17 00:00:00 2001 From: Fortune Ikechi Date: Tue, 5 May 2026 16:15:05 +0100 Subject: [PATCH 07/12] update the android multipeer page to distinguish between ble and wifi --- modules/android/pages/p2psync-multipeer.adoc | 380 ++----------------- modules/android/pages/supported-os.adoc | 20 +- 2 files changed, 60 insertions(+), 340 deletions(-) diff --git a/modules/android/pages/p2psync-multipeer.adoc b/modules/android/pages/p2psync-multipeer.adoc index 6c36648b9..a548eb8ed 100644 --- a/modules/android/pages/p2psync-multipeer.adoc +++ b/modules/android/pages/p2psync-multipeer.adoc @@ -72,33 +72,49 @@ See <>. === Transport Support .Transport support -[cols="1,1,2,1,2"] +[cols="1,1,2,2"] |=== -|Transport |Available from |Discovery |Minimum Android API |Notes +|Transport |Available from |Discovery |Notes |Wi-Fi |CBL 3.3 |DNS-SD (Bonjour) -|API 24 |Peers must connect to the same Wi-Fi network. |Bluetooth Low Energy |CBL 4.1 |BLE advertising and scanning -|API 29 -|Requires additional manifest permissions and runtime permission requests. See <>. +|Requires additional manifest permissions and runtime permission requests. +See <>. |=== +NOTE: When you configure both transports, the Multipeer Replicator automatically selects the best available transport for each peer and switches between them as reachability changes, preferring Wi-Fi over Bluetooth. +See <>. + === Supported Platforms -For Bluetooth transport, CBL supports Android API 29 and higher. +.Android API level requirements +[cols="2,1"] +|=== +|Feature |Minimum Android API + +|Couchbase Lite general support +|API 24 + +|Multipeer Replicator: Wi-Fi transport +|API 24 + +|Multipeer Replicator: Bluetooth transport +|API 29 +|=== + On API 29 and 30, Bluetooth requires the legacy `BLUETOOTH`, `BLUETOOTH_ADMIN`, and `ACCESS_FINE_LOCATION` permissions. On API 31 and higher, Bluetooth requires the runtime permissions `BLUETOOTH_SCAN`, `BLUETOOTH_ADVERTISE`, and `BLUETOOTH_CONNECT`. -See xref:android:supported-os.adoc[Supported Platforms] for the full platform support matrix. +See <> for the required permissions. [#platform-configuration] -=== Platform Configuration +=== Bluetooth Platform Configuration This section applies only if your application enables Bluetooth transport. Applications that use Wi-Fi only do not require these permissions. @@ -150,7 +166,6 @@ This section covers the key configurations you need to set up: === Collection Configurations - You can specify one or more collections available for replication when creating a `MultipeerReplicatorConfiguration`. For each collection, you'll create `MultipeerCollectionConfiguration` with the collection object and optionally configure a custom conflict resolver or any replication filters you want to use for the collection. @@ -233,9 +248,11 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ [#transports] === Transports -The `transports` property on `MultipeerReplicatorConfiguration` controls which transports the replicator uses for peer discovery and replication. The default is Wi-Fi only. +The `transports` property on `MultipeerReplicatorConfiguration` controls which transports the replicator uses for peer discovery and replication. + +==== Wi-Fi Only -To enable Bluetooth Low Energy alongside Wi-Fi, add `MultipeerTransport.BLUETOOTH` to the transports set. +Wi-Fi is the default transport. Existing applications continue to operate on Wi-Fi only after upgrading to CBL 4.1 with no code changes required. .Default (Wi-Fi only) [source,kotlin] @@ -243,11 +260,9 @@ To enable Bluetooth Low Energy alongside Wi-Fi, add `MultipeerTransport.BLUETOOT include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-config-transports-default", indent=0] ---- -.Wi-Fi and Bluetooth -[source,kotlin] ----- -include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-config-transports-both", indent=0] ----- +==== Bluetooth Only + +To use Bluetooth as the sole transport, set `transports` to `MultipeerTransport.BLUETOOTH`. Peers discover each other using BLE advertising and scanning rather than DNS-SD. .Bluetooth only [source,kotlin] @@ -255,13 +270,19 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-config-transports-bluetooth-only", indent=0] ---- -When you enable both transports, the replicator automatically selects the best available transport for each peer and switches between them as reachability changes. See <>. +==== Wi-Fi and Bluetooth with Automatic Switching -=== Create MultipeerReplicatorConfiguration +To enable both transports, set `transports` to include both `MultipeerTransport.WIFI` and `MultipeerTransport.BLUETOOTH`. The replicator prefers Wi-Fi and falls back to Bluetooth automatically when Wi-Fi is unavailable. See <>. +.Wi-Fi and Bluetooth +[source,kotlin] +---- +include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-config-transports-both", indent=0] +---- -The `MultipeerReplicatorConfiguration` can be created with a `peerGroupID` which is an identifier that identifies the peer-to-peer network used by the app, collection configurations, peer identity, and authenticator. +=== Create MultipeerReplicatorConfiguration +The `MultipeerReplicatorConfiguration` can be created with a `peerGroupID` which is an identifier that identifies the peer-to-peer network used by the app, collection configurations, peer identity, and authenticator. .Creating MultipeerReplicatorConfiguration [source,kotlin] @@ -339,10 +360,8 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ The `MultipeerReplicator` supports continuous mode, which allows it to operate in the background. - When the application is put into the background, the `MultipeerReplicator` will continue to operate in the background. - You should make sure that the application has the necessary permissions to run in the background and configure the `MultipeerReplicator` to support background operations. @@ -388,8 +407,6 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ ==== Peer's Document Replication - - .Peer's Document Replication Listener [source,kotlin] ---- @@ -397,18 +414,14 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ ---- - - == Peer Info === Peer Identifier - A unique `peerID`, which is a digest of the peer's identity certificate, identifies each peer. You can get your `peerID` from the `peerID` property of the `MultipeerReplicator`. - Getting peer ID [source,kotlin] ---- @@ -418,10 +431,8 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ === Neighbor Peers - You can get a list of current online peers' Identifiers from the `MultipeerReplicator` from the `neighborPeers` property. - .Getting neighbor peers [source,kotlin] ---- @@ -442,14 +453,11 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ == Logging - `LogDomain` sets up the logging of: - . Peer discovery log messages . Multipeer replication and mesh network management log messages - [source,kotlin] ---- include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-logdomain", indent=0] @@ -458,310 +466,4 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ == API Reference - -You can find https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-android}/couchbase-lite-android[Kotlin API References] here. - - - - - - - - - - - - - - -// == Overview - - -// The Multipeer P2P Replicator automatically advertises its presence, discovers other peers, -// and establishes connections for data replication with peers that share the same group identifier defined by the application. - - -// To maintain optimal connectivity, efficient data transport, and balanced workloads, the Multipeer P2P Replicator forms a dynamic mesh network among peers in the same group. -// It avoids redundant direct connections, evenly distributes connections across peers, and optimizes communication paths. -// The mesh network continuously adapts as peers join or leave. - - -// [mermaid] -// .... -// flowchart TB; -// id1[Android Device #1] -// id2[Android Device #2] -// id3[Android Device #3] -// id4[Android Device #4] -// id5[Android Device #5] -// id6[Android Device #6] -// id1<-->id2 -// id1<-->id3 -// id1<-->id4 -// id1<-->id5 -// id1<-->id6 -// id2<-->id3 -// id2<-->id4 -// id2<-->id5 -// id2<-->id6 -// id3<-->id4 -// id3<-->id5 -// id3<-->id6 -// id4<-->id5 -// id4<-->id6 -// id5<-->id6 -// .... - - - - -// == Configuration - - -// .Configuration for creating a Multipeer P2P Replicator -// [source,java] -// ---- -// public struct MultipeerReplicatorConfiguration { -// /// Identifier for discovering and connecting peers. -// public let peerGroupID: String - - -// /// Peer identity. -// /// @Note The identity’s certificate must be both server and client certificate. -// public let identity: TLSIdentity - - - - -// /// Peer authenticator. -// public let authenticator: MultipeerAuthenticator - - - - -// /// Collections to replicate. -// public let collections: [MultipeerCollectionConfiguration] - - - - -// /// Initialize the configuration with a peer group identifier, identity, -// /// authenticator and collections. -// public init(peerGroupID: String, -// identity: TLSIdentity, -// authenticator: MultipeerCertificateAuthenticator, -// collections: [MultipeerCollectionConfiguration]) -// } -// ---- - - - - - - - - - - -// TIP: In version 3.3.0, the recommended maximum number of peers in a mesh network is approximately 15. - - - - -// === Life Cycle - - -// Starting and stopping a peer-to-peer connection... - - - - -// === Listening for Changes - - -// Event types... - - - - -// `PeerDocumentReplication` - - - - -// == Example Use - - -// Here we will show how to instansiate a `MultipeerReplicatorConfiguration` configuration with self-signed certificates, and connect it to an example collection. - - -// [source,kotlin] -// ---- -// // Code sample -// ---- - - -// === MultipeerCollectionConfiguration - - -// `MultipeerCollectionConfiguration` specifies a collection and its associated settings. -// This includes a conflict resolver and replication filters. -// A list of these configurations is required to define which collections will be replicated within the peer group network. - - - - -// [source,kotlin] -// ---- -// /// Type Alias for Multipeer Replication Filter Function. -// public typealias MultipeerReplicationFilter = -// (PeerID, Document, DocumentFlags) -> Bool - - - - -// /// Multipeer Conflict Resolver Protocol. -// public protocol MultipeerConflictResolver { -// func resolve(peerID: PeerID, conflict: Conflict) -> Document? -// } - - -// /// Defines collection for replication including optional filters and -// /// custom conflict resolver. -// public struct MultipeerCollectionConfiguration { -// /// The collection. -// public let collection: Collection - - -// /// Document IDs filter. -// public var documentIDs: Array? - - -// /// Push filter. -// public var pushFilter: MultipeerReplicationFilter? - - -// /// Pull filter. -// public var pullFilter: MultipeerReplicationFilter? - - - - -// /// Custom conflict resolver. -// public var conflictResolver: MultipeerConflictResolver? - - - - -// /// Initialize with a collection. -// public init(collection: Collection) -// } -// ---- - - - - -// === Authenticator - - -// `MultipeerCertificateAuthenticator` - - -// === Peer Info - - -// `PeerInfo` provides information about the peer, including a peer unique identifier, the peer certificate, online status, replicator status, and its current `neighborPeers`. - - - - -// [source,kotlin] -// ---- - - -// ---- - - -// === Self-signed Certs - - -// .Creating a self-signed certificate that can be used as both client and server cert -// [source,kotlin] -// ---- -// /// Extended Key Usage for which the certified public key may be used. -// public struct KeyUsages: OptionSet { -// /// For Server Authentication -// public static let serverAuth = 0x40 - - -// /// For Client Authentication -// public static let clientAuth = 0x80 -// } - - -// /// TLS Identity -// public class TLSIdentity { -// /// Create a TLS identity from private key and certificate data. -// /// -// /// The private key and certificate data must be either in PEM or DER format. -// /// This method can be used to create an issuer identity for signing -// /// a certificate when generating a new TLS identity. -// public static func createIdentity(privateKey: Data, -// certificate: Data) throws -> TLSIdentity - - - - -// /// Generate a TLS identity, either self-signed or signed by an issuer identity. -// /// -// /// The `attributes` must include a common name (CN); otherwise an error -// /// will be thrown. -// /// -// /// The optional issuer identity may be specified to sign the certificate. -// /// The issuer identity can be created using -// /// `createIdentity(privateKeyData:certificateData:)`. If no issuer is specified, -// /// the certificate will be self-signed. -// /// -// /// If no the expiration date is specified, the default validity of one year -// /// will be applied. -// /// -// /// If a `label` is provided, the identity will be stored in the -// /// platform’s secure key storage under that label. -// public static func createIdentity(keyUsages: KeyUsages, -// attributes: [String: String], -// expiration: Date?, -// issuer: TLSIdentity?, -// label: String?) throws -> TLSIdentity - - - - - - - - -// @Deprecated, “Use createIdentity(keyUsages:attributes:expiration:issuer:label)” -// public static func createIdentity(server: Bool, -// attributes: [String: String], -// expiration: Date?, -// label: String) throws -> TLSIdentity -// } -// ---- - - - - - - -// === Logging - - -// `LogDomain` - - - - -// == API Reference - - -// *URL* \ No newline at end of file +You can find https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-android}/couchbase-lite-android[Kotlin API References] here. \ No newline at end of file diff --git a/modules/android/pages/supported-os.adoc b/modules/android/pages/supported-os.adoc index 38b4808e3..09c316282 100644 --- a/modules/android/pages/supported-os.adoc +++ b/modules/android/pages/supported-os.adoc @@ -1,4 +1,3 @@ - = Supported Operating System Versions :page-aliases: product/java-android-supported-os.adoc :page-role: -toc @@ -55,3 +54,22 @@ Couchbase does not test against, nor guarantee support for, uncertified Android |=== +[#feature-requirements] +== Feature Requirements + +Some features require a higher minimum API level than the general CBL requirement. + +.Multipeer Replicator API level requirements +[%autowidth.stretch] +|=== +|Feature |Minimum Android API |Notes + +|Multipeer Replicator: Wi-Fi transport +|API 24 +|Peers must connect to the same Wi-Fi network. + +|Multipeer Replicator: Bluetooth Low Energy transport +|API 29 +|Requires additional manifest permissions and runtime permission requests. +See xref:android:p2psync-multipeer.adoc#bluetooth-platform-configuration[Bluetooth Platform Configuration]. +|=== \ No newline at end of file From 66f0ef2123ba31b7097a7c32cda40742e7a5974e Mon Sep 17 00:00:00 2001 From: Fortune Ikechi Date: Tue, 5 May 2026 16:44:22 +0100 Subject: [PATCH 08/12] update sentence to table --- modules/android/pages/p2psync-multipeer.adoc | 18 ++++++++++++++---- modules/android/pages/supported-os.adoc | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/modules/android/pages/p2psync-multipeer.adoc b/modules/android/pages/p2psync-multipeer.adoc index a548eb8ed..7428a6f83 100644 --- a/modules/android/pages/p2psync-multipeer.adoc +++ b/modules/android/pages/p2psync-multipeer.adoc @@ -108,15 +108,25 @@ See <>. |API 29 |=== -On API 29 and 30, Bluetooth requires the legacy `BLUETOOTH`, `BLUETOOTH_ADMIN`, and `ACCESS_FINE_LOCATION` permissions. -On API 31 and higher, Bluetooth requires the runtime permissions `BLUETOOTH_SCAN`, `BLUETOOTH_ADVERTISE`, and `BLUETOOTH_CONNECT`. +.Bluetooth permission requirements by Android version +[cols="1,2"] +|=== +|Android version |Required permissions + +|API 29 and 30 +|`BLUETOOTH`, `BLUETOOTH_ADMIN`, `ACCESS_FINE_LOCATION` + +|API 31 and higher +|`BLUETOOTH_SCAN`, `BLUETOOTH_ADVERTISE`, `BLUETOOTH_CONNECT` +|=== -See <> for the required permissions. +See <> for the required manifest and runtime permissions. [#platform-configuration] === Bluetooth Platform Configuration -This section applies only if your application enables Bluetooth transport. Applications that use Wi-Fi only do not require these permissions. +This section applies only if your application enables Bluetooth transport. +Applications that use Wi-Fi only do not require these permissions. ==== Manifest Permissions diff --git a/modules/android/pages/supported-os.adoc b/modules/android/pages/supported-os.adoc index 09c316282..535d52f8e 100644 --- a/modules/android/pages/supported-os.adoc +++ b/modules/android/pages/supported-os.adoc @@ -57,7 +57,7 @@ Couchbase does not test against, nor guarantee support for, uncertified Android [#feature-requirements] == Feature Requirements -Some features require a higher minimum API level than the general CBL requirement. +Some features require a greater minimum API level to function than the general CBL requirement.. .Multipeer Replicator API level requirements [%autowidth.stretch] From 1f136416f650dc57cd16e8e9ae104f777237ba9d Mon Sep 17 00:00:00 2001 From: Fortune Ikechi Date: Wed, 6 May 2026 16:26:08 +0100 Subject: [PATCH 09/12] update maui for net 4.1 --- modules/csharp/pages/supported-os.adoc | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/modules/csharp/pages/supported-os.adoc b/modules/csharp/pages/supported-os.adoc index cd1e2c62c..62108e09d 100644 --- a/modules/csharp/pages/supported-os.adoc +++ b/modules/csharp/pages/supported-os.adoc @@ -1,4 +1,3 @@ - = Supported Operating System Versions :page-aliases: product/csharp-supported-os.adoc :page-role: -toc @@ -32,7 +31,7 @@ Plan to migrate your apps to use an appropriate alternative version. .Newer .NET Runtime Versions -- The *Minimum Runtime Version* column specifies the minimum required version for each .NET runtime. -Later versions, including .NET 10 and higher, also work because .NET provides backward compatibility. +Later versions, including .NET 11 and higher, also work because .NET provides backward compatibility. Couchbase Lite is built to be compatible with newer .NET runtime versions as they're released. If you encounter any issues with a newer .NET version, submit a support ticket. -- @@ -54,19 +53,19 @@ a| Windows 10 + (any Microsoft supported) | .NET Mac Catalyst -| 9.0 +| 10.0 a| MacOS 13 |WinUI -|9.0 +|10.0 |10.0.19041.0 |.NET iOS -|9.0 +|10.0 |15 |.NET Android -|9.0 +|10.0 |API 24 |=== @@ -88,6 +87,4 @@ The following run-times are compatible but are not QE tested, and so are not off | 8.0 |n/a -|=== - - +|=== \ No newline at end of file From eaab7b99fc4da81bd235da977c4f0952dd1cb5a2 Mon Sep 17 00:00:00 2001 From: Fortune Ikechi Date: Wed, 6 May 2026 17:28:21 +0100 Subject: [PATCH 10/12] update the multipeer pages --- modules/objc/pages/p2psync-multipeer.adoc | 65 ++++++++++++++++------ modules/swift/pages/p2psync-multipeer.adoc | 59 ++++++++++++++------ 2 files changed, 89 insertions(+), 35 deletions(-) diff --git a/modules/objc/pages/p2psync-multipeer.adoc b/modules/objc/pages/p2psync-multipeer.adoc index a0757c24f..f021dcf57 100644 --- a/modules/objc/pages/p2psync-multipeer.adoc +++ b/modules/objc/pages/p2psync-multipeer.adoc @@ -40,33 +40,50 @@ See <>. === Transport Support .Transport support -[cols="1,1,2,1,2"] +[cols="1,1,2,2"] |=== -|Transport |Available from |Discovery |Minimum iOS |Notes +|Transport |Available from |Discovery |Notes |Wi-Fi |CBL 3.3 |DNS-SD (Bonjour) -|iOS 10 |Peers must connect to the same Wi-Fi network. Requires `NSBonjourServices` and `NSLocalNetworkUsageDescription` in `Info.plist`. See <>. |Bluetooth Low Energy |CBL 4.1 |BLE advertising and scanning -|iOS 15 |Requires `NSBluetoothAlwaysUsageDescription` in `Info.plist`. See <>. |=== +NOTE: When you configure both transports, the Multipeer Replicator automatically selects the best available transport for each peer and switches between them as reachability changes, preferring Wi-Fi over Bluetooth. +See <>. + === Supported Platforms -For Wi-Fi transport, CBL supports iOS 10 and higher. +.iOS version requirements +[cols="2,1"] +|=== +|Feature |Minimum iOS + +|Couchbase Lite general support +|iOS 10 + +|Multipeer Replicator: Wi-Fi transport +|iOS 10 + +|Multipeer Replicator: Bluetooth transport +|iOS 15 +|=== -For Bluetooth transport, CBL supports iOS 15 and higher. +See <> for the required `Info.plist` keys. See xref:objc:supported-os.adoc[Supported Platforms] for the full platform support matrix. [#platform-configuration] -=== Platform Configuration +=== Bluetooth Platform Configuration + +This section applies only if your application enables Bluetooth transport. +Applications that use Wi-Fi only do not require these keys. iOS applications must declare the required keys in `Info.plist` for each transport they enable. You can also configure these settings through Xcode's Info configuration UI. @@ -184,21 +201,23 @@ include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-authen [#transports] === Transports -The `transports` property on `CBLMultipeerReplicatorConfiguration` controls which transports the replicator uses for peer discovery and replication. The default is Wi-Fi only. +The `transports` property on `CBLMultipeerReplicatorConfiguration` controls which transports the replicator uses for peer discovery and replication. The property type is `CBLMultipeerTransportSet`, an `NS_OPTIONS` bitmask. To enable Bluetooth Low Energy alongside Wi-Fi, combine the transport options with the bitwise OR operator. +==== Wi-Fi Only + +Wi-Fi is the default transport. Existing applications continue to operate on Wi-Fi only after upgrading to CBL 4.1 with no code changes required. + .Default (Wi-Fi only) [source,objc] ---- include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-config-transports-default", indent=0] ---- -.Wi-Fi and Bluetooth -[source,objc] ----- -include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-config-transports-both", indent=0] ----- +==== Bluetooth Only + +To use Bluetooth as the sole transport, set `transports` to `kCBLMultipeerTransportBluetooth`. Peers discover each other using BLE advertising and scanning rather than DNS-SD. .Bluetooth only [source,objc] @@ -206,7 +225,15 @@ include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-config include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-config-transports-bluetooth-only", indent=0] ---- -When you enable both transports, the replicator automatically selects the best available transport for each peer and switches between them as reachability changes. See <>. +==== Wi-Fi and Bluetooth with Automatic Switching + +To enable both transports, set `transports` to `kCBLMultipeerTransportWifi | kCBLMultipeerTransportBluetooth`. The replicator prefers Wi-Fi and falls back to Bluetooth automatically when Wi-Fi is unavailable. See <>. + +.Wi-Fi and Bluetooth +[source,objc] +---- +include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-config-transports-both", indent=0] +---- === Create MultipeerReplicatorConfiguration @@ -229,17 +256,21 @@ When `CBLMultipeerReplicator` is configured with both Wi-Fi and Bluetooth transp === Transport Preference -The replicator prefers Wi-Fi over Bluetooth when both transports can reach a peer. Bluetooth acts as a fallback when Wi-Fi cannot reach a peer. +The replicator prefers Wi-Fi over Bluetooth when both transports can reach a peer. +Bluetooth acts as a fallback when Wi-Fi cannot reach a peer. === Fallback to Bluetooth -For an individual peer, `CBLMultipeerReplicator` falls back to Bluetooth when the peer is no longer reachable over Wi-Fi. This can occur if the peer disables Wi-Fi, becomes unreachable on the local network, or if replication over Wi-Fi fails because of a network-related error. +For an individual peer, `CBLMultipeerReplicator` falls back to Bluetooth when the peer is no longer reachable over Wi-Fi. +This can occur if the peer disables Wi-Fi, becomes unreachable on the local network, or if replication over Wi-Fi fails because of a network-related error. In cases of connection or replication failure over Wi-Fi, `CBLMultipeerReplicator` performs a small number of retries before falling back to Bluetooth. === Return to Wi-Fi -If a peer becomes reachable over Wi-Fi while replication is active over Bluetooth, `CBLMultipeerReplicator` establishes a Wi-Fi connection in parallel with the existing Bluetooth connection. The Bluetooth connection remains active until the Wi-Fi connection is fully established and replication has resumed over Wi-Fi. This prevents any interruption in synchronization during the transition. +If a peer becomes reachable over Wi-Fi while replication is active over Bluetooth, `CBLMultipeerReplicator` establishes a Wi-Fi connection in parallel with the existing Bluetooth connection. +The Bluetooth connection remains active until the Wi-Fi connection is fully established and replication has resumed over Wi-Fi. +This prevents any interruption in synchronization during the transition. == Life Cycle diff --git a/modules/swift/pages/p2psync-multipeer.adoc b/modules/swift/pages/p2psync-multipeer.adoc index 49ebfc320..069656ecc 100644 --- a/modules/swift/pages/p2psync-multipeer.adoc +++ b/modules/swift/pages/p2psync-multipeer.adoc @@ -76,33 +76,50 @@ See <>. === Transport Support .Transport support -[cols="1,1,2,1,2"] +[cols="1,1,2,2"] |=== -|Transport |Available from |Discovery |Minimum iOS |Notes +|Transport |Available from |Discovery |Notes |Wi-Fi |CBL 3.3 |DNS-SD (Bonjour) -|iOS 10 |Peers must connect to the same Wi-Fi network. Requires `NSBonjourServices` and `NSLocalNetworkUsageDescription` in `Info.plist`. See <>. |Bluetooth Low Energy |CBL 4.1 |BLE advertising and scanning -|iOS 15 |Requires `NSBluetoothAlwaysUsageDescription` in `Info.plist`. See <>. |=== +NOTE: When you configure both transports, the Multipeer Replicator automatically selects the best available transport for each peer and switches between them as reachability changes, preferring Wi-Fi over Bluetooth. +See <>. + === Supported Platforms -For Wi-Fi transport, CBL supports iOS 10 and higher. +.iOS version requirements +[cols="2,1"] +|=== +|Feature |Minimum iOS + +|Couchbase Lite general support +|iOS 10 + +|Multipeer Replicator: Wi-Fi transport +|iOS 10 -For Bluetooth transport, CBL supports iOS 15 and higher. +|Multipeer Replicator: Bluetooth transport +|iOS 15 +|=== + +See <> for the required `Info.plist` keys. See xref:swift:supported-os.adoc[Supported Platforms] for the full platform support matrix. [#platform-configuration] -=== Platform Configuration +=== Bluetooth Platform Configuration + +This section applies only if your application enables Bluetooth transport. +Applications that use Wi-Fi only do not require these keys. iOS applications must declare the required keys in `Info.plist` for each transport they enable. You can also configure these settings through Xcode's Info configuration UI. @@ -194,7 +211,7 @@ When using self-signed certificates, implement your own certificate validation l === Peer Authenticator -MultpeerReplicator only supports certificate based authentication. +`MultipeerReplicator` only supports certificate based authentication. You can specify the authenticator in two ways: * certificate authentication callback @@ -221,9 +238,10 @@ include::swift:example$code_snippets/MultipeerReplicator.swift[tags="multipeer-a === Transports The `transports` property on `MultipeerReplicatorConfiguration` controls which transports the replicator uses for peer discovery and replication. -The default is Wi-Fi only. -To enable Bluetooth Low Energy alongside Wi-Fi, add `.bluetooth` to the transports set. +==== Wi-Fi Only + +Wi-Fi is the default transport. Existing applications continue to operate on Wi-Fi only after upgrading to CBL 4.1 with no code changes required. .Default (Wi-Fi only) [source,swift] @@ -231,11 +249,9 @@ To enable Bluetooth Low Energy alongside Wi-Fi, add `.bluetooth` to the transpor include::swift:example$code_snippets/MultipeerReplicator.swift[tags="multipeer-config-transports-default", indent=0] ---- -.Wi-Fi and Bluetooth -[source,swift] ----- -include::swift:example$code_snippets/MultipeerReplicator.swift[tags="multipeer-config-transports-both", indent=0] ----- +==== Bluetooth Only + +To use Bluetooth as the sole transport, set `transports` to `[.bluetooth]`. Peers discover each other using BLE advertising and scanning rather than DNS-SD. .Bluetooth only [source,swift] @@ -243,8 +259,15 @@ include::swift:example$code_snippets/MultipeerReplicator.swift[tags="multipeer-c include::swift:example$code_snippets/MultipeerReplicator.swift[tags="multipeer-config-transports-bluetooth-only", indent=0] ---- -When you enable both transports, the replicator automatically selects the best available transport for each peer and switches between them as reachability changes. -See <>. +==== Wi-Fi and Bluetooth with Automatic Switching + +To enable both transports, set `transports` to include both `.wifi` and `.bluetooth`. The replicator prefers Wi-Fi and falls back to Bluetooth automatically when Wi-Fi is unavailable. See <>. + +.Wi-Fi and Bluetooth +[source,swift] +---- +include::swift:example$code_snippets/MultipeerReplicator.swift[tags="multipeer-config-transports-both", indent=0] +---- === Create MultipeerReplicatorConfiguration @@ -377,7 +400,7 @@ include::swift:example$code_snippets/MultipeerReplicator.swift[tags="multipeer-n === Peer Info -The `PeerInfo` object provides information about a peer, including its identifier, certificate, online status, replicator status, neighbor peers, the transports on which the peer was discovered, and the transport presently used for replication. +The `PeerInfo` object provides information about a peer, including its identifier, certificate, online status, replicator status, neighbor peers, the transports on which the peer was discovered, and the transport currently used for replication. .Getting peer info [source,swift] From d273bc450f9ef1df5806aa5e9a7bff2ab897d545 Mon Sep 17 00:00:00 2001 From: Fortune Ikechi Date: Fri, 19 Jun 2026 11:23:27 +0100 Subject: [PATCH 11/12] update content --- modules/android/pages/p2psync-multipeer.adoc | 440 ++++++++++++++++--- 1 file changed, 382 insertions(+), 58 deletions(-) diff --git a/modules/android/pages/p2psync-multipeer.adoc b/modules/android/pages/p2psync-multipeer.adoc index 7428a6f83..0342dd3d0 100644 --- a/modules/android/pages/p2psync-multipeer.adoc +++ b/modules/android/pages/p2psync-multipeer.adoc @@ -9,8 +9,6 @@ ifdef::show_edition[:page-edition: Enterprise Edition] This approach requires minimal setup and automates peer discovery and connectivity management, making it simpler than xref:p2psync-websocket.adoc[active-passive P2P configurations]. - - [#introduction] == Introduction @@ -24,7 +22,8 @@ The dynamic mesh topology gives optimal peer connectivity and the lightweight an To maintain optimal connectivity, efficient data transport, and balanced workloads, the Multipeer Replicator forms a dynamic mesh network among peers in the same group. -The mesh network provides resilience through multiple communication pathways. If one connection fails, data can flow through alternative routes. +The mesh network provides resilience through multiple communication pathways. +If one connection fails, data can flow through alternative routes. It avoids redundant direct connections, evenly distributes connections across peers, and optimizes communication paths through intelligent routing. @@ -32,6 +31,9 @@ The mesh network continuously adapts as peers join or leave, automatically heali This self-organizing approach ensures reliable data synchronization even in challenging network conditions, where individual peer connections may be intermittent or unreliable. +NOTE: The Multipeer Replicator supports cross-platform replication between Android and iOS peers running Couchbase Lite 4.1 or higher. +An Android powered device and an iOS device using the same group ID, identity certificates from the same CA, and matching transport configuration can discover and replicate with each other over both Wi-Fi and Bluetooth. + // Mesh Diagram // [graphviz] // .... @@ -64,66 +66,42 @@ This self-organizing approach ensures reliable data synchronization even in chal == Prerequisites -The Multipeer Replicator supports two transports for peer discovery and replication: Wi-Fi and Bluetooth Low Energy (BLE). -Wi-Fi is enabled by default. -The enabled transports are configured through the replicator configuration. +The Multipeer Replicator supports two transports for peer discovery and replication: Wi-Fi and Bluetooth Low Energy (BLE). Wi-Fi is enabled by default. +Bluetooth is optional and you enable it through the replicator configuration. See <>. === Transport Support .Transport support -[cols="1,1,2,2"] +[cols="1,1,2,1,2"] |=== -|Transport |Available from |Discovery |Notes +|Transport |Available from |Discovery |Minimum Android API |Notes |Wi-Fi |CBL 3.3 |DNS-SD (Bonjour) +|API 24 |Peers must connect to the same Wi-Fi network. |Bluetooth Low Energy |CBL 4.1 |BLE advertising and scanning -|Requires additional manifest permissions and runtime permission requests. -See <>. -|=== - -NOTE: When you configure both transports, the Multipeer Replicator automatically selects the best available transport for each peer and switches between them as reachability changes, preferring Wi-Fi over Bluetooth. -See <>. - -=== Supported Platforms - -.Android API level requirements -[cols="2,1"] -|=== -|Feature |Minimum Android API - -|Couchbase Lite general support -|API 24 - -|Multipeer Replicator: Wi-Fi transport -|API 24 - -|Multipeer Replicator: Bluetooth transport |API 29 +|Requires additional manifest permissions and runtime permission requests. See <>. |=== -.Bluetooth permission requirements by Android version -[cols="1,2"] -|=== -|Android version |Required permissions +=== Supported Platforms -|API 29 and 30 -|`BLUETOOTH`, `BLUETOOTH_ADMIN`, `ACCESS_FINE_LOCATION` +For Wi-Fi transport, CBL supports Android API 24 and higher. -|API 31 and higher -|`BLUETOOTH_SCAN`, `BLUETOOTH_ADVERTISE`, `BLUETOOTH_CONNECT` -|=== +For Bluetooth transport, CBL supports Android API 29 and higher. +On API 29 and 30, Bluetooth uses the legacy `BLUETOOTH`, `BLUETOOTH_ADMIN`, and `ACCESS_FINE_LOCATION` permissions. +On API 31 and higher, Bluetooth uses the runtime permissions `BLUETOOTH_SCAN`, `BLUETOOTH_ADVERTISE`, and `BLUETOOTH_CONNECT`. -See <> for the required manifest and runtime permissions. +See xref:kotlin:supported-os.adoc[Supported Platforms] for the full platform support matrix. [#platform-configuration] -=== Bluetooth Platform Configuration +=== Platform Configuration This section applies only if your application enables Bluetooth transport. Applications that use Wi-Fi only do not require these permissions. @@ -163,6 +141,13 @@ Declare the required Bluetooth permissions in your `AndroidManifest.xml`. The pe On Android 12 (API 31) and higher, your application must request `BLUETOOTH_SCAN`, `BLUETOOTH_ADVERTISE`, and `BLUETOOTH_CONNECT` at runtime before starting the Multipeer Replicator. On Android 11 (API 30) and lower, your application must request `ACCESS_FINE_LOCATION` at runtime. +[CAUTION] +-- +On Android 13 (API 33) and higher, the runtime permission prompt is labelled *Nearby devices*, not Bluetooth. +You must still explicitly request `BLUETOOTH_SCAN`, `BLUETOOTH_ADVERTISE`, and `BLUETOOTH_CONNECT` at runtime on these devices. +Declaring permissions in the manifest alone is not sufficient: Android 13+ devices will not show a prompt and BLE sync will not work. +-- + .Requesting Bluetooth permissions at runtime [source,kotlin] ---- @@ -176,6 +161,7 @@ This section covers the key configurations you need to set up: === Collection Configurations + You can specify one or more collections available for replication when creating a `MultipeerReplicatorConfiguration`. For each collection, you'll create `MultipeerCollectionConfiguration` with the collection object and optionally configure a custom conflict resolver or any replication filters you want to use for the collection. @@ -258,11 +244,9 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ [#transports] === Transports -The `transports` property on `MultipeerReplicatorConfiguration` controls which transports the replicator uses for peer discovery and replication. - -==== Wi-Fi Only +The `transports` property on `MultipeerReplicatorConfiguration` controls which transports the replicator uses for peer discovery and replication. The default is Wi-Fi only. -Wi-Fi is the default transport. Existing applications continue to operate on Wi-Fi only after upgrading to CBL 4.1 with no code changes required. +To enable Bluetooth Low Energy alongside Wi-Fi, add `MultipeerTransport.BLUETOOTH` to the transports set. .Default (Wi-Fi only) [source,kotlin] @@ -270,30 +254,26 @@ Wi-Fi is the default transport. Existing applications continue to operate on Wi- include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-config-transports-default", indent=0] ---- -==== Bluetooth Only - -To use Bluetooth as the sole transport, set `transports` to `MultipeerTransport.BLUETOOTH`. Peers discover each other using BLE advertising and scanning rather than DNS-SD. - -.Bluetooth only +.Wi-Fi and Bluetooth [source,kotlin] ---- -include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-config-transports-bluetooth-only", indent=0] +include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-config-transports-both", indent=0] ---- -==== Wi-Fi and Bluetooth with Automatic Switching - -To enable both transports, set `transports` to include both `MultipeerTransport.WIFI` and `MultipeerTransport.BLUETOOTH`. The replicator prefers Wi-Fi and falls back to Bluetooth automatically when Wi-Fi is unavailable. See <>. - -.Wi-Fi and Bluetooth +.Bluetooth only [source,kotlin] ---- -include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-config-transports-both", indent=0] +include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-config-transports-bluetooth-only", indent=0] ---- +When you enable both transports, the replicator automatically selects the best available transport for each peer and switches between them as reachability changes. See <>. + === Create MultipeerReplicatorConfiguration + The `MultipeerReplicatorConfiguration` can be created with a `peerGroupID` which is an identifier that identifies the peer-to-peer network used by the app, collection configurations, peer identity, and authenticator. + .Creating MultipeerReplicatorConfiguration [source,kotlin] ---- @@ -370,8 +350,10 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ The `MultipeerReplicator` supports continuous mode, which allows it to operate in the background. + When the application is put into the background, the `MultipeerReplicator` will continue to operate in the background. + You should make sure that the application has the necessary permissions to run in the background and configure the `MultipeerReplicator` to support background operations. @@ -423,15 +405,16 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-document-replication-listener", indent=0] ---- - == Peer Info === Peer Identifier + A unique `peerID`, which is a digest of the peer's identity certificate, identifies each peer. You can get your `peerID` from the `peerID` property of the `MultipeerReplicator`. + Getting peer ID [source,kotlin] ---- @@ -441,8 +424,10 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ === Neighbor Peers + You can get a list of current online peers' Identifiers from the `MultipeerReplicator` from the `neighborPeers` property. + .Getting neighbor peers [source,kotlin] ---- @@ -461,13 +446,46 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ ---- +[#lbl-testing] +== Testing + +[#testing-device-requirements] +=== Device Requirements + +The Multipeer Replicator requires physical devices for end-to-end testing. +Android emulators and iOS simulators do not support Bluetooth Low Energy. +Test on real devices connected to the same Wi-Fi network for Wi-Fi transport, or in close physical proximity for Bluetooth. + +[#testing-isolating-ble] +=== Isolating the Bluetooth Path + +To verify that BLE transport is working independently of Wi-Fi: + +. Enable airplane mode on both test devices to disable Wi-Fi and cellular. +. Re-enable Bluetooth on both devices (airplane mode allows this on both Android and iOS). +. Start the Multipeer Replicator on both devices. +. Confirm replication completes using the BLE transport only. + +This approach removes any ambiguity about which transport is carrying the data. + +[#testing-android-doze] +=== Android Doze Mode + +Android Doze mode can silently suspend background network activity, including Multipeer Replication, when a device is idle. +During testing, keep the screen on or disable battery optimization for your test application to prevent Doze from interfering with replication. +In production, see <> for configuration guidance. + + == Logging + `LogDomain` sets up the logging of: + . Peer discovery log messages . Multipeer replication and mesh network management log messages + [source,kotlin] ---- include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-logdomain", indent=0] @@ -476,4 +494,310 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ == API Reference -You can find https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-android}/couchbase-lite-android[Kotlin API References] here. \ No newline at end of file + +You can find https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-kotlin}{empty}/couchbase-lite-kotlin[Kotlin API References] here. + + + + + + + + + + + + + + +// == Overview + + +// The Multipeer P2P Replicator automatically advertises its presence, discovers other peers, +// and establishes connections for data replication with peers that share the same group identifier defined by the application. + + +// To maintain optimal connectivity, efficient data transport, and balanced workloads, the Multipeer P2P Replicator forms a dynamic mesh network among peers in the same group. +// It avoids redundant direct connections, evenly distributes connections across peers, and optimizes communication paths. +// The mesh network continuously adapts as peers join or leave. + + +// [mermaid] +// .... +// flowchart TB; +// id1[Android Device #1] +// id2[Android Device #2] +// id3[Android Device #3] +// id4[Android Device #4] +// id5[Android Device #5] +// id6[Android Device #6] +// id1<-->id2 +// id1<-->id3 +// id1<-->id4 +// id1<-->id5 +// id1<-->id6 +// id2<-->id3 +// id2<-->id4 +// id2<-->id5 +// id2<-->id6 +// id3<-->id4 +// id3<-->id5 +// id3<-->id6 +// id4<-->id5 +// id4<-->id6 +// id5<-->id6 +// .... + + + + +// == Configuration + + +// .Configuration for creating a Multipeer P2P Replicator +// [source,java] +// ---- +// public struct MultipeerReplicatorConfiguration { +// /// Identifier for discovering and connecting peers. +// public let peerGroupID: String + + +// /// Peer identity. +// /// @Note The identity’s certificate must be both server and client certificate. +// public let identity: TLSIdentity + + + + +// /// Peer authenticator. +// public let authenticator: MultipeerAuthenticator + + + + +// /// Collections to replicate. +// public let collections: [MultipeerCollectionConfiguration] + + + + +// /// Initialize the configuration with a peer group identifier, identity, +// /// authenticator and collections. +// public init(peerGroupID: String, +// identity: TLSIdentity, +// authenticator: MultipeerCertificateAuthenticator, +// collections: [MultipeerCollectionConfiguration]) +// } +// ---- + + + + + + + + + + +// TIP: In version 3.3.0, the recommended maximum number of peers in a mesh network is approximately 15. + + + + +// === Life Cycle + + +// Starting and stopping a peer-to-peer connection... + + + + +// === Listening for Changes + + +// Event types... + + + + +// `PeerDocumentReplication` + + + + +// == Example Use + + +// Here we will show how to instansiate a `MultipeerReplicatorConfiguration` configuration with self-signed certificates, and connect it to an example collection. + + +// [source,kotlin] +// ---- +// // Code sample +// ---- + + +// === MultipeerCollectionConfiguration + + +// `MultipeerCollectionConfiguration` specifies a collection and its associated settings. +// This includes a conflict resolver and replication filters. +// A list of these configurations is required to define which collections will be replicated within the peer group network. + + + + +// [source,kotlin] +// ---- +// /// Type Alias for Multipeer Replication Filter Function. +// public typealias MultipeerReplicationFilter = +// (PeerID, Document, DocumentFlags) -> Bool + + + + +// /// Multipeer Conflict Resolver Protocol. +// public protocol MultipeerConflictResolver { +// func resolve(peerID: PeerID, conflict: Conflict) -> Document? +// } + + +// /// Defines collection for replication including optional filters and +// /// custom conflict resolver. +// public struct MultipeerCollectionConfiguration { +// /// The collection. +// public let collection: Collection + + +// /// Document IDs filter. +// public var documentIDs: Array? + + +// /// Push filter. +// public var pushFilter: MultipeerReplicationFilter? + + +// /// Pull filter. +// public var pullFilter: MultipeerReplicationFilter? + + + + +// /// Custom conflict resolver. +// public var conflictResolver: MultipeerConflictResolver? + + + + +// /// Initialize with a collection. +// public init(collection: Collection) +// } +// ---- + + + + +// === Authenticator + + +// `MultipeerCertificateAuthenticator` + + +// === Peer Info + + +// `PeerInfo` provides information about the peer, including a peer unique identifier, the peer certificate, online status, replicator status, and its current `neighborPeers`. + + + + +// [source,kotlin] +// ---- + + +// ---- + + +// === Self-signed Certs + + +// .Creating a self-signed certificate that can be used as both client and server cert +// [source,kotlin] +// ---- +// /// Extended Key Usage for which the certified public key may be used. +// public struct KeyUsages: OptionSet { +// /// For Server Authentication +// public static let serverAuth = 0x40 + + +// /// For Client Authentication +// public static let clientAuth = 0x80 +// } + + +// /// TLS Identity +// public class TLSIdentity { +// /// Create a TLS identity from private key and certificate data. +// /// +// /// The private key and certificate data must be either in PEM or DER format. +// /// This method can be used to create an issuer identity for signing +// /// a certificate when generating a new TLS identity. +// public static func createIdentity(privateKey: Data, +// certificate: Data) throws -> TLSIdentity + + + + +// /// Generate a TLS identity, either self-signed or signed by an issuer identity. +// /// +// /// The `attributes` must include a common name (CN); otherwise an error +// /// will be thrown. +// /// +// /// The optional issuer identity may be specified to sign the certificate. +// /// The issuer identity can be created using +// /// `createIdentity(privateKeyData:certificateData:)`. If no issuer is specified, +// /// the certificate will be self-signed. +// /// +// /// If no the expiration date is specified, the default validity of one year +// /// will be applied. +// /// +// /// If a `label` is provided, the identity will be stored in the +// /// platform’s secure key storage under that label. +// public static func createIdentity(keyUsages: KeyUsages, +// attributes: [String: String], +// expiration: Date?, +// issuer: TLSIdentity?, +// label: String?) throws -> TLSIdentity + + + + + + + + +// @Deprecated, “Use createIdentity(keyUsages:attributes:expiration:issuer:label)” +// public static func createIdentity(server: Bool, +// attributes: [String: String], +// expiration: Date?, +// label: String) throws -> TLSIdentity +// } +// ---- + + + + + + +// === Logging + + +// `LogDomain` + + + + +// == API Reference + + +// *URL* From 41807f3eac01a1d5403965c3755f0e21e923228e Mon Sep 17 00:00:00 2001 From: Fortune Ikechi Date: Thu, 25 Jun 2026 15:03:39 +0100 Subject: [PATCH 12/12] update multipeer sync --- modules/android/pages/p2psync-multipeer.adoc | 362 +------------------ modules/objc/pages/p2psync-multipeer.adoc | 6 +- modules/swift/pages/p2psync-multipeer.adoc | 40 +- 3 files changed, 21 insertions(+), 387 deletions(-) diff --git a/modules/android/pages/p2psync-multipeer.adoc b/modules/android/pages/p2psync-multipeer.adoc index 0342dd3d0..37bbed313 100644 --- a/modules/android/pages/p2psync-multipeer.adoc +++ b/modules/android/pages/p2psync-multipeer.adoc @@ -34,35 +34,6 @@ This self-organizing approach ensures reliable data synchronization even in chal NOTE: The Multipeer Replicator supports cross-platform replication between Android and iOS peers running Couchbase Lite 4.1 or higher. An Android powered device and an iOS device using the same group ID, identity certificates from the same CA, and matching transport configuration can discover and replicate with each other over both Wi-Fi and Bluetooth. -// Mesh Diagram -// [graphviz] -// .... -// graph { -// layout="circo"; -// id1[ label="Android Device #1" shape="square" ] -// id2[ label="Android Device #2" shape="square" ] -// id3[ label="Android Device #3" shape="square" ] -// id4[ label="Android Device #4" shape="square" ] -// id5[ label="Android Device #5" shape="square" ] -// id6[ label="Android Device #6" shape="square" ] -// id1 -- id2 -// id1 -- id3 -// id1 -- id4 -// id1 -- id5 -// id1 -- id6 -// id2 -- id3 -// id2 -- id4 -// id2 -- id5 -// id2 -- id6 -// id3 -- id4 -// id3 -- id5 -// id3 -- id6 -// id4 -- id5 -// id4 -- id6 -// id5 -- id6 -// } -// .... - == Prerequisites @@ -134,6 +105,12 @@ Declare the required Bluetooth permissions in your `AndroidManifest.xml`. The pe + + + ---- @@ -141,6 +118,8 @@ Declare the required Bluetooth permissions in your `AndroidManifest.xml`. The pe On Android 12 (API 31) and higher, your application must request `BLUETOOTH_SCAN`, `BLUETOOTH_ADVERTISE`, and `BLUETOOTH_CONNECT` at runtime before starting the Multipeer Replicator. On Android 11 (API 30) and lower, your application must request `ACCESS_FINE_LOCATION` at runtime. +On Android 13 (API 33) and higher, your application must also request `NEARBY_WIFI_DEVICES` at runtime for Wi-Fi peer discovery. + [CAUTION] -- On Android 13 (API 33) and higher, the runtime permission prompt is labelled *Nearby devices*, not Bluetooth. @@ -260,6 +239,8 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-config-transports-both", indent=0] ---- +NOTE: Bluetooth has lower throughput and higher latency than Wi-Fi, and its reliability can decrease as more peers join the Bluetooth network. We recommend using Wi-Fi as the primary transport for multipeer sync, with Bluetooth as a fallback, rather than relying on Bluetooth alone. + .Bluetooth only [source,kotlin] ---- @@ -313,20 +294,6 @@ If a peer becomes reachable over Wi-Fi while replication is active over Bluetoot include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-replicator", indent=0] ---- - -// === Permissions - -// Android requires specific permissions for DNS-SD operations. -// You can get the necessary permissions using: - - -// .Getting necessary permissions -// [source,kotlin] -// ---- -// include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/MultipeerExamples.kt[tags="multipeer-permissions", indent=0] -// ---- - - === Start .Starting MultipeerReplicator @@ -461,7 +428,7 @@ Test on real devices connected to the same Wi-Fi network for Wi-Fi transport, or To verify that BLE transport is working independently of Wi-Fi: -. Enable airplane mode on both test devices to disable Wi-Fi and cellular. +. Enable airplane mode on both test devices to disable Wi-Fi. . Re-enable Bluetooth on both devices (airplane mode allows this on both Android and iOS). . Start the Multipeer Replicator on both devices. . Confirm replication completes using the BLE transport only. @@ -495,309 +462,4 @@ include::example$kotlin_snippets/app/src/main/kotlin/com/couchbase/codesnippets/ == API Reference -You can find https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-kotlin}{empty}/couchbase-lite-kotlin[Kotlin API References] here. - - - - - - - - - - - - - - -// == Overview - - -// The Multipeer P2P Replicator automatically advertises its presence, discovers other peers, -// and establishes connections for data replication with peers that share the same group identifier defined by the application. - - -// To maintain optimal connectivity, efficient data transport, and balanced workloads, the Multipeer P2P Replicator forms a dynamic mesh network among peers in the same group. -// It avoids redundant direct connections, evenly distributes connections across peers, and optimizes communication paths. -// The mesh network continuously adapts as peers join or leave. - - -// [mermaid] -// .... -// flowchart TB; -// id1[Android Device #1] -// id2[Android Device #2] -// id3[Android Device #3] -// id4[Android Device #4] -// id5[Android Device #5] -// id6[Android Device #6] -// id1<-->id2 -// id1<-->id3 -// id1<-->id4 -// id1<-->id5 -// id1<-->id6 -// id2<-->id3 -// id2<-->id4 -// id2<-->id5 -// id2<-->id6 -// id3<-->id4 -// id3<-->id5 -// id3<-->id6 -// id4<-->id5 -// id4<-->id6 -// id5<-->id6 -// .... - - - - -// == Configuration - - -// .Configuration for creating a Multipeer P2P Replicator -// [source,java] -// ---- -// public struct MultipeerReplicatorConfiguration { -// /// Identifier for discovering and connecting peers. -// public let peerGroupID: String - - -// /// Peer identity. -// /// @Note The identity’s certificate must be both server and client certificate. -// public let identity: TLSIdentity - - - - -// /// Peer authenticator. -// public let authenticator: MultipeerAuthenticator - - - - -// /// Collections to replicate. -// public let collections: [MultipeerCollectionConfiguration] - - - - -// /// Initialize the configuration with a peer group identifier, identity, -// /// authenticator and collections. -// public init(peerGroupID: String, -// identity: TLSIdentity, -// authenticator: MultipeerCertificateAuthenticator, -// collections: [MultipeerCollectionConfiguration]) -// } -// ---- - - - - - - - - - - -// TIP: In version 3.3.0, the recommended maximum number of peers in a mesh network is approximately 15. - - - - -// === Life Cycle - - -// Starting and stopping a peer-to-peer connection... - - - - -// === Listening for Changes - - -// Event types... - - - - -// `PeerDocumentReplication` - - - - -// == Example Use - - -// Here we will show how to instansiate a `MultipeerReplicatorConfiguration` configuration with self-signed certificates, and connect it to an example collection. - - -// [source,kotlin] -// ---- -// // Code sample -// ---- - - -// === MultipeerCollectionConfiguration - - -// `MultipeerCollectionConfiguration` specifies a collection and its associated settings. -// This includes a conflict resolver and replication filters. -// A list of these configurations is required to define which collections will be replicated within the peer group network. - - - - -// [source,kotlin] -// ---- -// /// Type Alias for Multipeer Replication Filter Function. -// public typealias MultipeerReplicationFilter = -// (PeerID, Document, DocumentFlags) -> Bool - - - - -// /// Multipeer Conflict Resolver Protocol. -// public protocol MultipeerConflictResolver { -// func resolve(peerID: PeerID, conflict: Conflict) -> Document? -// } - - -// /// Defines collection for replication including optional filters and -// /// custom conflict resolver. -// public struct MultipeerCollectionConfiguration { -// /// The collection. -// public let collection: Collection - - -// /// Document IDs filter. -// public var documentIDs: Array? - - -// /// Push filter. -// public var pushFilter: MultipeerReplicationFilter? - - -// /// Pull filter. -// public var pullFilter: MultipeerReplicationFilter? - - - - -// /// Custom conflict resolver. -// public var conflictResolver: MultipeerConflictResolver? - - - - -// /// Initialize with a collection. -// public init(collection: Collection) -// } -// ---- - - - - -// === Authenticator - - -// `MultipeerCertificateAuthenticator` - - -// === Peer Info - - -// `PeerInfo` provides information about the peer, including a peer unique identifier, the peer certificate, online status, replicator status, and its current `neighborPeers`. - - - - -// [source,kotlin] -// ---- - - -// ---- - - -// === Self-signed Certs - - -// .Creating a self-signed certificate that can be used as both client and server cert -// [source,kotlin] -// ---- -// /// Extended Key Usage for which the certified public key may be used. -// public struct KeyUsages: OptionSet { -// /// For Server Authentication -// public static let serverAuth = 0x40 - - -// /// For Client Authentication -// public static let clientAuth = 0x80 -// } - - -// /// TLS Identity -// public class TLSIdentity { -// /// Create a TLS identity from private key and certificate data. -// /// -// /// The private key and certificate data must be either in PEM or DER format. -// /// This method can be used to create an issuer identity for signing -// /// a certificate when generating a new TLS identity. -// public static func createIdentity(privateKey: Data, -// certificate: Data) throws -> TLSIdentity - - - - -// /// Generate a TLS identity, either self-signed or signed by an issuer identity. -// /// -// /// The `attributes` must include a common name (CN); otherwise an error -// /// will be thrown. -// /// -// /// The optional issuer identity may be specified to sign the certificate. -// /// The issuer identity can be created using -// /// `createIdentity(privateKeyData:certificateData:)`. If no issuer is specified, -// /// the certificate will be self-signed. -// /// -// /// If no the expiration date is specified, the default validity of one year -// /// will be applied. -// /// -// /// If a `label` is provided, the identity will be stored in the -// /// platform’s secure key storage under that label. -// public static func createIdentity(keyUsages: KeyUsages, -// attributes: [String: String], -// expiration: Date?, -// issuer: TLSIdentity?, -// label: String?) throws -> TLSIdentity - - - - - - - - -// @Deprecated, “Use createIdentity(keyUsages:attributes:expiration:issuer:label)” -// public static func createIdentity(server: Bool, -// attributes: [String: String], -// expiration: Date?, -// label: String) throws -> TLSIdentity -// } -// ---- - - - - - - -// === Logging - - -// `LogDomain` - - - - -// == API Reference - - -// *URL* +You can find https://docs.couchbase.com/mobile/{major}.{minor}.{maintenance-kotlin}{empty}/couchbase-lite-kotlin[Kotlin API References] here. \ No newline at end of file diff --git a/modules/objc/pages/p2psync-multipeer.adoc b/modules/objc/pages/p2psync-multipeer.adoc index f021dcf57..416f579a9 100644 --- a/modules/objc/pages/p2psync-multipeer.adoc +++ b/modules/objc/pages/p2psync-multipeer.adoc @@ -66,10 +66,10 @@ See <>. |Feature |Minimum iOS |Couchbase Lite general support -|iOS 10 +|iOS 15 |Multipeer Replicator: Wi-Fi transport -|iOS 10 +|iOS 15 |Multipeer Replicator: Bluetooth transport |iOS 15 @@ -235,6 +235,8 @@ To enable both transports, set `transports` to `kCBLMultipeerTransportWifi | kCB include::objc:example$code_snippets/MultipeerReplicator.m[tags="multipeer-config-transports-both", indent=0] ---- +NOTE: Bluetooth has lower throughput and higher latency than Wi-Fi, and its reliability can decrease as more peers join the Bluetooth network. We recommend using Wi-Fi as the primary transport for multipeer sync, with Bluetooth as a fallback, rather than relying on Bluetooth alone. + === Create MultipeerReplicatorConfiguration The `CBLMultipeerReplicatorConfiguration` is created with a `peerGroupID` that identifies the peer-to-peer network used by the app, collection configurations, peer identity, and authenticator. diff --git a/modules/swift/pages/p2psync-multipeer.adoc b/modules/swift/pages/p2psync-multipeer.adoc index 069656ecc..8c690f0eb 100644 --- a/modules/swift/pages/p2psync-multipeer.adoc +++ b/modules/swift/pages/p2psync-multipeer.adoc @@ -34,38 +34,6 @@ The mesh network continuously adapts as peers join or leave, automatically heali This self-organizing approach ensures reliable data synchronization even in challenging network conditions, where individual peer connections may be intermittent or unreliable. -// Mesh Diagram - -// [mesh] -// .... -// graph { -// layout="circo"; -// id1[ label="iOS Device #1" shape="square" ] -// id2[ label="iOS Device #2" shape="square" ] -// id3[ label="iOS Device #3" shape="square" ] -// id4[ label="iOS Device #4" shape="square" ] -// id5[ label="iOS Device #5" shape="square" ] -// id6[ label="iOS Device #6" shape="square" ] -// id1 -- id2 -// id1 -- id3 -// id1 -- id4 -// id1 -- id5 -// id1 -- id6 -// id2 -- id3 -// id2 -- id4 -// id2 -- id5 -// id2 -- id6 -// id3 -- id4 -// id3 -- id5 -// id3 -- id6 -// id4 -- id5 -// id4 -- id6 -// id5 -- id6 -// } -// .... - - - == Prerequisites The Multipeer Replicator supports two transports for peer discovery and replication: Wi-Fi and Bluetooth Low Energy (BLE). @@ -102,10 +70,10 @@ See <>. |Feature |Minimum iOS |Couchbase Lite general support -|iOS 10 +|iOS 15 |Multipeer Replicator: Wi-Fi transport -|iOS 10 +|iOS 15 |Multipeer Replicator: Bluetooth transport |iOS 15 @@ -269,9 +237,11 @@ To enable both transports, set `transports` to include both `.wifi` and `.blueto include::swift:example$code_snippets/MultipeerReplicator.swift[tags="multipeer-config-transports-both", indent=0] ---- +NOTE: Bluetooth has lower throughput and higher latency than Wi-Fi, and its reliability can decrease as more peers join the Bluetooth network. We recommend using Wi-Fi as the primary transport for multipeer sync, with Bluetooth as a fallback, rather than relying on Bluetooth alone. + === Create MultipeerReplicatorConfiguration -The `MultipeerReplicatorConfiguration` can be created with a `peerGroupID` which is an identity identifies the Peer-to-peer network used by the app, collection configurations, peer identity, and authenticator. +The `MultipeerReplicatorConfiguration` can be created with a `peerGroupID` which identifies the peer-to-peer network used by the app, collection configurations, peer identity, and authenticator. .Creating MultipeerReplicatorConfiguration