diff --git a/mobile/ios-assets/notif.wav b/mobile/ios-assets/notif.wav new file mode 100644 index 0000000..58aa957 Binary files /dev/null and b/mobile/ios-assets/notif.wav differ diff --git a/mobile/scripts/add-share-extension.rb b/mobile/scripts/add-share-extension.rb index e6f0c70..08ce1e8 100644 --- a/mobile/scripts/add-share-extension.rb +++ b/mobile/scripts/add-share-extension.rb @@ -112,5 +112,25 @@ appex = ext.product_reference build_file = embed.add_file_reference(appex) build_file.settings = { 'ATTRIBUTES' => ['RemoveHeadersOnCopy'] } +# ── Bundle the custom notification sound (notif.wav) into the App target ───────────────────────────── +# ios-patch.sh copied it to App/App/notif.wav. Add it as a resource so it ships in the bundle root where +# APNs can find it (the server sends sound:'notif.wav'). Tolerant: never fail the build over the sound. +begin + snd_path = File.join(APP_DIR, 'App', 'notif.wav') + if File.exist?(snd_path) + grp = project.main_group.find_subpath('App', false) || project.main_group + already = app.resources_build_phase.files.any? { |bf| bf.file_ref && bf.file_ref.respond_to?(:display_name) && bf.file_ref.display_name == 'notif.wav' } + unless already + snd_ref = grp.new_reference(snd_path) + app.resources_build_phase.add_file_reference(snd_ref) + end + puts "Notification sound bundled into App resources: notif.wav" + else + puts " (notif.wav not in project — sound not bundled)" + end +rescue => e + puts " (notif.wav bundling skipped: #{e.message})" +end + project.save puts "Share Extension injected: #{EXT_NAME} (#{EXT_BUNDLE}) embedded in #{APP_TARGET}" diff --git a/mobile/scripts/ios-patch.sh b/mobile/scripts/ios-patch.sh index 8008800..e96562a 100644 --- a/mobile/scripts/ios-patch.sh +++ b/mobile/scripts/ios-patch.sh @@ -101,6 +101,14 @@ echo "Entitlements: aps-environment=production ensured in $ENT" # the speaker (headphones/Bluetooth still win when connected). The helper is tolerant and exits 0 even if # the template differs, so it NEVER fails the build. First-pass fix — if WebRTC re-grabs the session # mid-call on device, we follow up with a plugin that re-asserts .overrideOutputAudioPort(.speaker). +# ── Bundle the custom notification sound so chat/call pushes have an explicit tone ────────────────── +# APNs plays the sound named in the push payload (the server sends sound:'notif.wav'). The file must be a +# resource in the app bundle ROOT; copy it in here — add-share-extension.rb then adds it to the App +# target's "Copy Bundle Resources". iOS accepts a PCM .wav (<30s) for a notification sound. +SND_SRC="mobile/ios-assets/notif.wav" +SND_DST="mobile/ios/App/App/notif.wav" +if [ -f "$SND_SRC" ]; then cp "$SND_SRC" "$SND_DST" && echo "Copied notification sound -> $SND_DST"; else echo " (notif.wav source missing — sound not bundled)"; fi + AD="mobile/ios/App/App/AppDelegate.swift" if [ -f "$AD" ]; then echo "Patching AppDelegate audio session" diff --git a/server/push.js b/server/push.js index 48d3e45..4a65c10 100644 --- a/server/push.js +++ b/server/push.js @@ -88,7 +88,9 @@ function sendApns(token, payload) { let client; try { client = http2.connect(apnsCfg.host); } catch (_) { return resolve({}); } client.on('error', () => { try { client.close(); } catch (_) {} resolve({}); }); - const body = JSON.stringify({ aps: { alert: { title: payload.title || 'Biz Connect', body: payload.body || '' }, sound: 'default' }, ...(payload.data || {}) }); + // Custom bundled sound (notif.wav, shipped in the app via ios-patch.sh + add-share-extension.rb) gives + // chat/call notifications an explicit, distinctive tone. A call site may override via payload.sound. + const body = JSON.stringify({ aps: { alert: { title: payload.title || 'Biz Connect', body: payload.body || '' }, sound: payload.sound || 'notif.wav' }, ...(payload.data || {}) }); const req = client.request({ ':method': 'POST', ':path': '/3/device/' + token, authorization: 'bearer ' + apnsToken(), 'apns-topic': apnsCfg.bundle, 'apns-push-type': 'alert' }); let status = 0; req.on('response', (h) => { status = h[':status']; });