Skip to content

Commit 56c00cd

Browse files
authored
Merge pull request #17 from CodePandaaAI/refactor-network-services
feat: prepare Sync360 v0.1.0 with native Windows/iOS support and new sharing UX
2 parents 8c53300 + fb2f686 commit 56c00cd

102 files changed

Lines changed: 4634 additions & 1022 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ios.yml

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
name: iOS
2+
3+
on:
4+
push:
5+
paths:
6+
- ".github/workflows/ios.yml"
7+
- "iosApp/**"
8+
- "shared/**"
9+
- "gradle/**"
10+
- "build.gradle.kts"
11+
- "settings.gradle.kts"
12+
- "gradle.properties"
13+
pull_request:
14+
paths:
15+
- ".github/workflows/ios.yml"
16+
- "iosApp/**"
17+
- "shared/**"
18+
- "gradle/**"
19+
- "build.gradle.kts"
20+
- "settings.gradle.kts"
21+
- "gradle.properties"
22+
workflow_dispatch:
23+
inputs:
24+
build_signed_ipa:
25+
description: "Build a development-signed IPA for registered iPhones"
26+
required: true
27+
type: boolean
28+
default: false
29+
30+
permissions:
31+
contents: read
32+
33+
concurrency:
34+
group: ios-${{ github.workflow }}-${{ github.ref }}
35+
cancel-in-progress: true
36+
37+
jobs:
38+
simulator-app:
39+
name: Build iOS Simulator app
40+
runs-on: macos-26
41+
timeout-minutes: 60
42+
43+
steps:
44+
- name: Check out source
45+
uses: actions/checkout@v6
46+
47+
- name: Set up JDK 23
48+
uses: actions/setup-java@v5
49+
with:
50+
distribution: temurin
51+
java-version: "23"
52+
53+
- name: Set up Gradle
54+
uses: gradle/actions/setup-gradle@v6
55+
56+
- name: Select Xcode 26.4
57+
run: sudo xcode-select --switch /Applications/Xcode_26.4.app/Contents/Developer
58+
59+
- name: Show Apple toolchain
60+
run: xcodebuild -version
61+
62+
- name: Build unsigned Simulator app
63+
run: |
64+
xcodebuild \
65+
-project iosApp/iosApp.xcodeproj \
66+
-scheme iosApp \
67+
-configuration Debug \
68+
-sdk iphonesimulator \
69+
-destination "generic/platform=iOS Simulator" \
70+
-derivedDataPath build/ios-simulator \
71+
CODE_SIGNING_ALLOWED=NO \
72+
TEAM_ID= \
73+
build
74+
75+
- name: Package Simulator app
76+
run: |
77+
APP_PATH="build/ios-simulator/Build/Products/Debug-iphonesimulator/Sync360.app"
78+
test -d "$APP_PATH"
79+
ditto -c -k --sequesterRsrc --keepParent "$APP_PATH" Sync360-iOS-Simulator.zip
80+
81+
- name: Upload Simulator app
82+
uses: actions/upload-artifact@v4
83+
with:
84+
name: Sync360-iOS-Simulator
85+
path: Sync360-iOS-Simulator.zip
86+
if-no-files-found: error
87+
retention-days: 14
88+
89+
signed-iphone-ipa:
90+
name: Build signed iPhone IPA
91+
if: github.event_name == 'workflow_dispatch' && inputs.build_signed_ipa
92+
runs-on: macos-26
93+
timeout-minutes: 60
94+
env:
95+
IOS_DEVELOPMENT_CERTIFICATE_BASE64: ${{ secrets.IOS_DEVELOPMENT_CERTIFICATE_BASE64 }}
96+
IOS_DEVELOPMENT_CERTIFICATE_PASSWORD: ${{ secrets.IOS_DEVELOPMENT_CERTIFICATE_PASSWORD }}
97+
IOS_DEVELOPMENT_PROVISIONING_PROFILE_BASE64: ${{ secrets.IOS_DEVELOPMENT_PROVISIONING_PROFILE_BASE64 }}
98+
IOS_TEAM_ID: ${{ secrets.IOS_TEAM_ID }}
99+
100+
steps:
101+
- name: Check out source
102+
uses: actions/checkout@v6
103+
104+
- name: Set up JDK 23
105+
uses: actions/setup-java@v5
106+
with:
107+
distribution: temurin
108+
java-version: "23"
109+
110+
- name: Set up Gradle
111+
uses: gradle/actions/setup-gradle@v6
112+
113+
- name: Select Xcode 26.4
114+
run: sudo xcode-select --switch /Applications/Xcode_26.4.app/Contents/Developer
115+
116+
- name: Require Apple signing secrets
117+
shell: bash
118+
run: |
119+
missing=0
120+
for secret_name in \
121+
IOS_DEVELOPMENT_CERTIFICATE_BASE64 \
122+
IOS_DEVELOPMENT_CERTIFICATE_PASSWORD \
123+
IOS_DEVELOPMENT_PROVISIONING_PROFILE_BASE64 \
124+
IOS_TEAM_ID
125+
do
126+
if [ -z "${!secret_name:-}" ]; then
127+
echo "::error::Missing GitHub Actions secret: $secret_name"
128+
missing=1
129+
fi
130+
done
131+
exit "$missing"
132+
133+
- name: Install development certificate and provisioning profile
134+
shell: bash
135+
run: |
136+
CERTIFICATE_PATH="$RUNNER_TEMP/ios-development.p12"
137+
PROFILE_PATH="$RUNNER_TEMP/ios-development.mobileprovision"
138+
PROFILE_PLIST="$RUNNER_TEMP/ios-development-profile.plist"
139+
KEYCHAIN_PATH="$RUNNER_TEMP/sync360-signing.keychain-db"
140+
KEYCHAIN_PASSWORD="$(openssl rand -hex 24)"
141+
142+
printf '%s' "$IOS_DEVELOPMENT_CERTIFICATE_BASE64" | base64 --decode > "$CERTIFICATE_PATH"
143+
printf '%s' "$IOS_DEVELOPMENT_PROVISIONING_PROFILE_BASE64" | base64 --decode > "$PROFILE_PATH"
144+
145+
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
146+
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
147+
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
148+
security import "$CERTIFICATE_PATH" \
149+
-P "$IOS_DEVELOPMENT_CERTIFICATE_PASSWORD" \
150+
-A \
151+
-t cert \
152+
-f pkcs12 \
153+
-k "$KEYCHAIN_PATH"
154+
security set-key-partition-list \
155+
-S apple-tool:,apple: \
156+
-s \
157+
-k "$KEYCHAIN_PASSWORD" \
158+
"$KEYCHAIN_PATH"
159+
security list-keychains -d user -s "$KEYCHAIN_PATH"
160+
161+
security cms -D -i "$PROFILE_PATH" > "$PROFILE_PLIST"
162+
PROFILE_UUID="$(/usr/libexec/PlistBuddy -c 'Print :UUID' "$PROFILE_PLIST")"
163+
PROFILE_NAME="$(/usr/libexec/PlistBuddy -c 'Print :Name' "$PROFILE_PLIST")"
164+
APPLICATION_IDENTIFIER="$(/usr/libexec/PlistBuddy -c 'Print :Entitlements:application-identifier' "$PROFILE_PLIST")"
165+
BUNDLE_IDENTIFIER="${APPLICATION_IDENTIFIER#*.}"
166+
167+
mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles"
168+
cp "$PROFILE_PATH" "$HOME/Library/MobileDevice/Provisioning Profiles/$PROFILE_UUID.mobileprovision"
169+
170+
echo "IOS_PROFILE_NAME=$PROFILE_NAME" >> "$GITHUB_ENV"
171+
echo "IOS_BUNDLE_IDENTIFIER=$BUNDLE_IDENTIFIER" >> "$GITHUB_ENV"
172+
echo "IOS_ARCHIVE_PATH=$RUNNER_TEMP/Sync360.xcarchive" >> "$GITHUB_ENV"
173+
echo "IOS_EXPORT_PATH=$RUNNER_TEMP/ios-export" >> "$GITHUB_ENV"
174+
175+
security find-identity -v -p codesigning "$KEYCHAIN_PATH"
176+
177+
- name: Archive signed iPhone app
178+
shell: bash
179+
run: |
180+
xcodebuild \
181+
-project iosApp/iosApp.xcodeproj \
182+
-scheme iosApp \
183+
-configuration Debug \
184+
-destination "generic/platform=iOS" \
185+
-archivePath "$IOS_ARCHIVE_PATH" \
186+
TEAM_ID="$IOS_TEAM_ID" \
187+
PRODUCT_BUNDLE_IDENTIFIER="$IOS_BUNDLE_IDENTIFIER" \
188+
DEVELOPMENT_TEAM="$IOS_TEAM_ID" \
189+
CODE_SIGN_STYLE=Manual \
190+
CODE_SIGN_IDENTITY="Apple Development" \
191+
PROVISIONING_PROFILE_SPECIFIER="$IOS_PROFILE_NAME" \
192+
archive
193+
194+
- name: Export signed IPA
195+
shell: bash
196+
run: |
197+
EXPORT_OPTIONS="$RUNNER_TEMP/ExportOptions.plist"
198+
cat > "$EXPORT_OPTIONS" <<EOF
199+
<?xml version="1.0" encoding="UTF-8"?>
200+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
201+
<plist version="1.0">
202+
<dict>
203+
<key>method</key>
204+
<string>debugging</string>
205+
<key>signingStyle</key>
206+
<string>manual</string>
207+
<key>teamID</key>
208+
<string>$IOS_TEAM_ID</string>
209+
<key>provisioningProfiles</key>
210+
<dict>
211+
<key>$IOS_BUNDLE_IDENTIFIER</key>
212+
<string>$IOS_PROFILE_NAME</string>
213+
</dict>
214+
</dict>
215+
</plist>
216+
EOF
217+
218+
xcodebuild \
219+
-exportArchive \
220+
-archivePath "$IOS_ARCHIVE_PATH" \
221+
-exportOptionsPlist "$EXPORT_OPTIONS" \
222+
-exportPath "$IOS_EXPORT_PATH"
223+
224+
test -n "$(find "$IOS_EXPORT_PATH" -maxdepth 1 -name '*.ipa' -print -quit)"
225+
226+
- name: Upload signed IPA
227+
uses: actions/upload-artifact@v4
228+
with:
229+
name: Sync360-iPhone-Development-IPA
230+
path: ${{ runner.temp }}/ios-export/*.ipa
231+
if-no-files-found: error
232+
retention-days: 14

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ captures/
2424

2525
# Signing secrets
2626
*.jks
27+
*.jkis
2728
*.keystore
2829
keystore.properties
2930

CHANGELOG.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
1010

1111
- Android-first manual rebuild with shared Compose Multiplatform Send and Receive UI.
1212
- Android DNS-SD/mDNS discovery and registration through `NsdManager`.
13-
- Desktop DNS-SD/mDNS discovery and registration through JmDNS.
13+
- Windows DNS-SD/mDNS discovery and registration through the operating system `dnsapi.dll` API on all interfaces.
14+
- Current macOS/Linux DNS-SD/mDNS discovery and registration through JmDNS on eligible IPv4 and IPv6 LAN addresses.
15+
- Separate discovery and registration lifecycle states shared by Android, Desktop, the controller, and UI.
1416
- Stable per-install device identity and advertised dynamic HTTP/file-transfer ports.
1517
- Text offers, receiver Accept/Decline, text transfer, Copy, and Clear.
1618
- Android and Desktop multiple-file selection and metadata offers.
@@ -22,6 +24,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
2224
- Shared transfer buffer/timeout constants, currently using a 512 KiB payload buffer.
2325
- Compose Desktop startup, platform DI implementations, native file dialog, clipboard, and Downloads actions.
2426
- Navigation 3 adaptive 50/50 Send/Receive scene for wider windows.
27+
- Application-lifetime network startup and state-driven connection repair.
28+
- Enabled iOS device and Apple-silicon Simulator targets with native Bonjour discovery, document selection, clipboard, Files-visible storage, and streamed TCP transfer implementations.
29+
- Added an iOS-only GitHub Actions workflow for an unsigned Simulator app and optional development-signed iPhone IPA.
30+
- Prepared version `0.1.0` across Android, Desktop, and iOS; added private Android release signing configuration and a permanent Windows MSI upgrade identity.
2531
- Public architecture, development, roadmap, security, privacy, and contribution documentation.
2632

2733
### Changed
@@ -30,13 +36,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
3036
- Separated Ktor HTTP offer/control messages from raw TCP file bytes.
3137
- Reused one TCP connection for the complete accepted multi-file batch instead of opening one connection per file.
3238
- Removed per-file flush-and-acknowledgement waits so an accepted batch can stream continuously before one final receiver result.
39+
- Moved network startup from the Send ViewModel to the Android and Desktop application entry points.
40+
- Derived the 60-second discovery window from the platform-reported running state.
41+
- Made Android repair advance through NSD callbacks and made JVM cleanup retain JmDNS instances that fail to close.
42+
- Restricted discovery Reload and full connection repair to compatible discovery and registration states.
43+
- Selected the Windows-native discovery backend at Desktop DI startup while retaining JmDNS for macOS and Linux.
44+
- Used the JDK Foreign Function and Memory API for Windows interop without adding a third-party native bridge.
45+
- Made Windows discovery process native add and TTL-zero removal notifications so the nearby-device list can update during an active browse.
46+
- Moved Windows discovery out of its initial loading state as soon as the operating system accepts the asynchronous browse request.
47+
- Confirmed in an initial Windows 11 Ethernet test that Android and Windows advertisements appeared promptly and were removed after the corresponding app closed.
48+
- Aligned Kotlin 2.4.10, Android Gradle Plugin 9.1.1, and Gradle 9.3.1 within their documented compatibility ranges while retaining Android API 37.
3349
- Positioned the project around direct local-network nearby sharing rather than chat or cloud sync.
3450

3551
### Known limitations
3652

3753
- No stable public release yet.
3854
- No authentication, encryption, transfer/session token, or cryptographic integrity verification.
39-
- No byte percentage, speed, ETA, retry, pause/resume, or interrupted-transfer recovery.
55+
- No speed, ETA, retry, pause/resume, or interrupted-transfer recovery; transfer progress currently shows batch-wide whole-byte percentage.
4056
- Foreground/background and network-change lifecycle handling are incomplete.
4157
- Desktop support needs broader operating-system, adapter, firewall, and router validation.
42-
- Automated transfer coverage is minimal; iOS is inactive.
58+
- Automated transfer coverage is minimal; iOS physical-device discovery and transfer are unverified.

CODE_OF_CONDUCT.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Project maintainers may remove comments, close issues, reject contributions, or
3030

3131
If you see a problem, report it privately to the maintainer.
3232

33-
Maintainer contact: TODO: add private contact email
33+
Until a dedicated contact email is added, contact the maintainer privately through the GitHub or LinkedIn profile linked in `README.md`.
3434

3535
## Scope
3636

CONTRIBUTING.md

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,29 @@ The project is not looking for giant rewrites right now. The most useful contrib
66

77
## Current project status
88

9-
Current working slice:
9+
Implemented today:
1010

11-
- Android NSD discovery.
12-
- Dynamic Ktor server port advertisement.
13-
- Ktor client/server ping request.
14-
- Experimental receiver Accept/Decline state.
11+
- Android nearby discovery and registration through `NsdManager`.
12+
- Windows nearby discovery and registration through the system DNS-SD API.
13+
- Current macOS/Linux discovery and registration through JmDNS.
14+
- Direct text and multi-file transfer between nearby devices.
15+
- Shared Compose UI for Android and Desktop.
16+
- Enabled iOS source implementation for Bonjour discovery, text/file transfer, selection, clipboard, and Files-visible storage.
1517

16-
Not built yet:
18+
Important current limitations:
1719

18-
- Real file transfer.
19-
- Direct text sending.
20-
- Desktop rebuilt networking flow.
21-
- Security/session validation.
22-
- Production-ready UX.
20+
- Local transfers are not authenticated or encrypted.
21+
- Background and automatic network-change lifecycle handling is incomplete.
22+
- Desktop networking has not been broadly validated across operating systems, adapters, VPNs, and routers.
23+
- iOS physical-device discovery and transfer behavior is not yet validated.
2324

2425
Please keep that status in mind when opening issues or PRs.
2526

2627
## Local setup
2728

2829
Prerequisites:
2930

30-
- JDK 17
31+
- JDK 23
3132
- Android Studio or IntelliJ IDEA
3233
- Android SDK
3334
- Gradle wrapper from this repository
@@ -53,13 +54,13 @@ On Windows:
5354
./gradlew.bat :androidApp:assembleDebug
5455
```
5556

56-
Desktop shell:
57+
Run Desktop:
5758

5859
```bash
5960
./gradlew :desktopApp:run
6061
```
6162

62-
The rebuilt networking flow is currently Android-first, so desktop behavior may lag behind Android.
63+
Android remains the primary reference implementation. Platform networking behavior can differ where operating-system APIs require it.
6364

6465
## Before you start
6566

@@ -69,7 +70,7 @@ For anything large, open an issue first. Examples:
6970

7071
- changing architecture boundaries
7172
- changing discovery behavior
72-
- adding file transfer
73+
- changing the transfer protocol
7374
- adding security
7475
- changing Gradle/KMP target setup
7576
- adding persistence/database code
@@ -82,6 +83,7 @@ Good early contributions:
8283
- Add screenshots or demo GIFs.
8384
- Improve error messages and logs.
8485
- Test Android discovery on different devices/routers.
86+
- Test Windows discovery across Ethernet, Wi-Fi, VPN, and virtual adapters.
8587
- Improve host address selection, especially IPv4 vs IPv6.
8688
- Clean up naming where the current intent is obvious.
8789
- Add small tests around pure Kotlin models/controllers when useful.
@@ -153,6 +155,8 @@ For networking changes, manual validation notes are useful:
153155

154156
- one Android device
155157
- two Android devices on same Wi-Fi
158+
- Android and Desktop on the same network
159+
- Desktop adapter and operating-system version
156160
- Android hotspot if relevant
157161
- what happened on sender
158162
- what happened on receiver

0 commit comments

Comments
 (0)