speaker: make AudioRoute a real Capacitor plugin PACKAGE so it registers (device log: has:0)
Device telemetry proved the app-embedded AudioRoute class never registered (not in
Capacitor.Plugins) — appending a CAPBridgedPlugin to AppDelegate.swift gets stripped/undiscovered
in release builds. The plugins that DO register (Share, Camera, Filesystem) are all npm packages
wired by cap sync. So AudioRoute is now a local plugin package (mobile/plugins/audio-route,
file: dep in mobile/package.json) with a podspec + CAPBridgedPlugin Swift — cap sync adds its pod
and Capacitor registers it like the others. load() sets the launch speaker default; setSpeaker({on})
overrides the output port. inject-audio.js no longer injects the plugin class (would duplicate);
it keeps only the AppDelegate launch default as a fallback.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
require 'json'
|
||||
|
||||
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'AudioRoutePlugin'
|
||||
s.version = package['version']
|
||||
s.summary = package['description']
|
||||
s.license = package['license']
|
||||
s.homepage = 'https://bizgaze.com'
|
||||
s.author = 'BizGaze'
|
||||
s.source = { :git => 'https://bizgaze.com/audio-route.git', :tag => s.version.to_s }
|
||||
s.source_files = 'ios/Sources/**/*.{swift,h,m}'
|
||||
s.ios.deployment_target = '14.0'
|
||||
s.dependency 'Capacitor'
|
||||
s.swift_version = '5.1'
|
||||
end
|
||||
@@ -0,0 +1,35 @@
|
||||
import Foundation
|
||||
import Capacitor
|
||||
import AVFoundation
|
||||
|
||||
// Earpiece <-> speaker toggle for calls. Registered by cap sync as a normal Capacitor plugin package, so it
|
||||
// appears as window.Capacitor.Plugins.AudioRoute (unlike an app-embedded class, which gets stripped/not
|
||||
// discovered in release builds). setSpeaker({on}) overrides the AVAudioSession output port.
|
||||
@objc(AudioRoutePlugin)
|
||||
public class AudioRoutePlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
public let identifier = "AudioRoutePlugin"
|
||||
public let jsName = "AudioRoute"
|
||||
public let pluginMethods: [CAPPluginMethod] = [
|
||||
CAPPluginMethod(name: "setSpeaker", returnType: CAPPluginReturnPromise)
|
||||
]
|
||||
|
||||
override public func load() {
|
||||
// Default calls to the loudspeaker when the plugin initialises (iOS uses the quiet earpiece otherwise).
|
||||
let session = AVAudioSession.sharedInstance()
|
||||
try? session.setCategory(.playAndRecord, mode: .voiceChat, options: [.defaultToSpeaker, .allowBluetooth, .allowBluetoothA2DP])
|
||||
try? session.setActive(true)
|
||||
}
|
||||
|
||||
@objc func setSpeaker(_ call: CAPPluginCall) {
|
||||
let on = call.getBool("on") ?? true
|
||||
let session = AVAudioSession.sharedInstance()
|
||||
do {
|
||||
try session.setCategory(.playAndRecord, mode: .voiceChat, options: [.allowBluetooth, .allowBluetoothA2DP])
|
||||
try session.setActive(true)
|
||||
try session.overrideOutputAudioPort(on ? .speaker : .none)
|
||||
call.resolve(["route": on ? "speaker" : "earpiece"])
|
||||
} catch {
|
||||
call.reject(error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "audio-route",
|
||||
"version": "1.0.0",
|
||||
"description": "iOS earpiece/speaker audio route toggle for Biz Connect",
|
||||
"main": "dist/plugin.cjs.js",
|
||||
"module": "dist/esm/index.js",
|
||||
"types": "dist/esm/index.d.ts",
|
||||
"author": "BizGaze",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"dist/",
|
||||
"ios/",
|
||||
"AudioRoutePlugin.podspec"
|
||||
],
|
||||
"capacitor": {
|
||||
"ios": {
|
||||
"src": "ios"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@capacitor/core": "^7.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": "^7.0.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user