diff --git a/bitchat.xcodeproj/project.pbxproj b/bitchat.xcodeproj/project.pbxproj
index c5f1e7dc..5eaf6abc 100644
--- a/bitchat.xcodeproj/project.pbxproj
+++ b/bitchat.xcodeproj/project.pbxproj
@@ -255,6 +255,8 @@
DEVELOPMENT_TEAM = L3N5LHJD5Y;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = bitchat/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = bitchat;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@@ -264,9 +266,12 @@
PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat;
PRODUCT_NAME = bitchat;
SDKROOT = iphoneos;
- SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 1;
};
name = Debug;
};
@@ -282,6 +287,8 @@
DEVELOPMENT_TEAM = L3N5LHJD5Y;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = bitchat/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = bitchat;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@@ -291,9 +298,12 @@
PRODUCT_BUNDLE_IDENTIFIER = chat.bitchat;
PRODUCT_NAME = bitchat;
SDKROOT = iphoneos;
- SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 1;
};
name = Release;
};
diff --git a/bitchat/Info.plist b/bitchat/Info.plist
index e33081c5..4943de82 100644
--- a/bitchat/Info.plist
+++ b/bitchat/Info.plist
@@ -39,9 +39,13 @@
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
- UIInterfaceOrientationPortraitUpsideDown
+
+ UISupportedInterfaceOrientations~ipad
+
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
diff --git a/bitchat/Services/BluetoothMeshService.swift b/bitchat/Services/BluetoothMeshService.swift
index 174359c8..9eab05bf 100644
--- a/bitchat/Services/BluetoothMeshService.swift
+++ b/bitchat/Services/BluetoothMeshService.swift
@@ -54,6 +54,7 @@ class BluetoothMeshService: NSObject {
private var announcedToPeers = Set() // Track which peers we've announced to
private var announcedPeers = Set() // Track peers who have already been announced
private var processedKeyExchanges = Set() // Track processed key exchanges to prevent duplicates
+ private var intentionalDisconnects = Set() // Track peripherals we're disconnecting intentionally
// Store-and-forward message cache
private struct StoredMessage {
@@ -1322,6 +1323,16 @@ class BluetoothMeshService: NSObject {
if senderID != "unknown" && senderID != myPeerID {
// Check if we need to update peripheral mapping from the specific peripheral that sent this
if let peripheral = peripheral {
+ // Check if we already have a different peripheral connected for this peer
+ if let existingPeripheral = self.connectedPeripherals[senderID],
+ existingPeripheral != peripheral {
+ // We have a duplicate connection - disconnect the newer one
+ // print("[DEBUG] Duplicate connection detected for \(senderID), keeping existing")
+ intentionalDisconnects.insert(peripheral.identifier.uuidString)
+ centralManager.cancelPeripheralConnection(peripheral)
+ return
+ }
+
// Find if this peripheral is currently mapped with a temp ID
if let tempID = self.connectedPeripherals.first(where: { $0.value == peripheral })?.key,
tempID.count > 8 { // It's a temp ID
@@ -1748,6 +1759,8 @@ extension BluetoothMeshService: CBCentralManagerDelegate {
let tempID = peripheral.identifier.uuidString
connectedPeripherals[tempID] = peripheral
+ // Don't show connected message yet - wait for key exchange
+ // This prevents the connect/disconnect/connect pattern
// Request RSSI reading
peripheral.readRSSI()
@@ -1762,6 +1775,13 @@ extension BluetoothMeshService: CBCentralManagerDelegate {
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
let peripheralID = peripheral.identifier.uuidString
+ // Check if this was an intentional disconnect
+ if intentionalDisconnects.contains(peripheralID) {
+ intentionalDisconnects.remove(peripheralID)
+ // Don't process this disconnect further
+ return
+ }
+
// Implement exponential backoff for failed connections
if error != nil {
let attempts = connectionAttempts[peripheralID] ?? 0
diff --git a/connection_fixes.md b/connection_fixes.md
new file mode 100644
index 00000000..27753399
--- /dev/null
+++ b/connection_fixes.md
@@ -0,0 +1,41 @@
+# Connection Stability Fixes for BluetoothMeshService
+
+## Issues Causing Disconnect/Reconnect
+
+1. **Simultaneous Connection Attempts**: Both devices acting as central and peripheral can create duplicate connections
+2. **Temporary ID Management**: Using peripheral UUIDs as temporary IDs causes confusion
+3. **Premature State Updates**: Peer list updates happen before connections are fully established
+4. **Aggressive Disconnect Handling**: Peers are removed immediately on disconnect without grace period
+
+## Recommended Fixes
+
+### 1. Implement Connection Deduplication
+- Track ongoing connection attempts by peer ID
+- Reject duplicate connections from same peer
+- Use deterministic logic to decide which side maintains connection (e.g., compare peer IDs)
+
+### 2. Improve Peer State Management
+- Add connection states: CONNECTING, CONNECTED, DISCONNECTING
+- Only show "joined" after key exchange AND announce received
+- Add grace period before showing "left" messages (e.g., 5 seconds)
+
+### 3. Fix Temporary ID Handling
+- Don't add temp IDs to activePeers
+- Only update peer lists after receiving real peer ID
+- Use a separate pendingPeripherals dictionary
+
+### 4. Consolidate Key Exchange and Announce
+- Send key exchange and announce as atomic operation
+- Wait for both before considering peer "connected"
+- Add sequence numbers to prevent duplicate processing
+
+### 5. Add Connection Stability Timer
+- Don't show "joined" until connection stable for 1 second
+- Buffer rapid connect/disconnect cycles
+- Implement exponential backoff for reconnection attempts
+
+## Implementation Priority
+1. Fix duplicate connection handling (highest impact)
+2. Add connection grace period
+3. Improve state management
+4. Consolidate initialization messages
\ No newline at end of file
diff --git a/project.yml b/project.yml
index b24b1cc5..d5dcdade 100644
--- a/project.yml
+++ b/project.yml
@@ -34,11 +34,8 @@ targets:
UIColorName: Black
UISupportedInterfaceOrientations:
- UIInterfaceOrientationPortrait
- - UIInterfaceOrientationPortraitUpsideDown
- - UIInterfaceOrientationLandscapeLeft
- - UIInterfaceOrientationLandscapeRight
settings:
- PRODUCT_BUNDLE_IDENTIFIER: com.bitchat.app
+ PRODUCT_BUNDLE_IDENTIFIER: chat.bitchat
INFOPLIST_FILE: bitchat/Info.plist
ENABLE_PREVIEWS: YES
SWIFT_VERSION: 5.0
@@ -49,4 +46,4 @@ targets:
CODE_SIGNING_REQUIRED: YES
CODE_SIGNING_ALLOWED: YES
ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
- ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS: YES
\ No newline at end of file
+ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS: YES