react-native-acoustic-connect-beta 18.0.38 → 18.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AcousticConnectRN.podspec +22 -0
- package/CHANGELOG.md +2 -0
- package/README.md +68 -9
- package/android/src/main/assets/ConnectBasicConfig.properties +1 -1
- package/cli/doctor.mjs +181 -34
- package/cli/index.mjs +20 -8
- package/cli/ios/add_push_extensions.rb +21 -1
- package/cli/ios/setup-push.mjs +5 -0
- package/ios/AcousticConnectRNConfig.json +1 -0
- package/package.json +1 -1
- package/plugin/build/index.d.ts +12 -5
- package/plugin/build/index.d.ts.map +1 -1
- package/plugin/build/index.js +22 -7
- package/plugin/build/index.js.map +1 -1
- package/plugin/build/withConnectAndroidConfig.d.ts +14 -0
- package/plugin/build/withConnectAndroidConfig.d.ts.map +1 -1
- package/plugin/build/withConnectAndroidConfig.js +97 -1
- package/plugin/build/withConnectAndroidConfig.js.map +1 -1
- package/plugin/build/withConnectIosSigning.d.ts +34 -0
- package/plugin/build/withConnectIosSigning.d.ts.map +1 -0
- package/plugin/build/withConnectIosSigning.js +114 -0
- package/plugin/build/withConnectIosSigning.js.map +1 -0
- package/plugin/build/withConnectNSE.d.ts +7 -0
- package/plugin/build/withConnectNSE.d.ts.map +1 -1
- package/plugin/build/withConnectNSE.js.map +1 -1
- package/plugin/src/index.ts +30 -8
- package/plugin/src/withConnectAndroidConfig.ts +87 -1
- package/plugin/src/withConnectIosSigning.ts +107 -0
- package/plugin/src/withConnectNSE.ts +7 -0
|
@@ -6,7 +6,13 @@
|
|
|
6
6
|
// be provided in an agreement with Acoustic, L.P. Any unauthorized copying or
|
|
7
7
|
// distribution of content from this file is prohibited.
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
withAppBuildGradle,
|
|
11
|
+
withDangerousMod,
|
|
12
|
+
type ConfigPlugin,
|
|
13
|
+
} from '@expo/config-plugins'
|
|
14
|
+
import * as fs from 'fs'
|
|
15
|
+
import * as path from 'path'
|
|
10
16
|
import type { ConnectPluginProps } from './withConnectNSE'
|
|
11
17
|
|
|
12
18
|
// The Gradle snippet that runs the SDK's config.gradle. config.gradle reads
|
|
@@ -68,3 +74,83 @@ export const withConnectAndroidConfig: ConfigPlugin<ConnectPluginProps> = (
|
|
|
68
74
|
cfg.modResults.contents = appendConfigGradleApply(cfg.modResults.contents)
|
|
69
75
|
return cfg
|
|
70
76
|
})
|
|
77
|
+
|
|
78
|
+
/** True when ConnectConfig.json at `projectRoot` has Connect.PushEnabled === true. */
|
|
79
|
+
function isPushEnabled(projectRoot: string): boolean {
|
|
80
|
+
const configPath = path.join(projectRoot, 'ConnectConfig.json')
|
|
81
|
+
if (!fs.existsSync(configPath)) return false
|
|
82
|
+
try {
|
|
83
|
+
const parsed = JSON.parse(fs.readFileSync(configPath, 'utf8')) as {
|
|
84
|
+
Connect?: { PushEnabled?: unknown }
|
|
85
|
+
}
|
|
86
|
+
return parsed.Connect?.PushEnabled === true
|
|
87
|
+
} catch {
|
|
88
|
+
return false
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Fail fast at prebuild when push is enabled but `android.package` is absent
|
|
94
|
+
* from the configured `google-services.json`. FCM matches its client by package
|
|
95
|
+
* name, so a mismatch makes Gradle fail much later at
|
|
96
|
+
* `:app:processDebugGoogleServices` with the opaque "No matching client found
|
|
97
|
+
* for package name …" — and only after a full prebuild + Gradle config. Surface
|
|
98
|
+
* it here, at the moment the native project is (re)generated, with the exact fix
|
|
99
|
+
* (CA-144135 §10b). `acoustic-connect doctor` performs the same check up front;
|
|
100
|
+
* this is the guard for a developer who runs `expo run:android` directly.
|
|
101
|
+
*
|
|
102
|
+
* Only the genuine MISMATCH throws. A missing package / googleServicesFile is
|
|
103
|
+
* left to `doctor` and the build itself (this mod doesn't duplicate those).
|
|
104
|
+
*/
|
|
105
|
+
export const withConnectAndroidGoogleServicesMatch: ConfigPlugin<
|
|
106
|
+
ConnectPluginProps
|
|
107
|
+
> = (config) =>
|
|
108
|
+
withDangerousMod(config, [
|
|
109
|
+
'android',
|
|
110
|
+
async (cfg) => {
|
|
111
|
+
const projectRoot = cfg._internal?.projectRoot
|
|
112
|
+
if (!projectRoot || !isPushEnabled(projectRoot)) return cfg
|
|
113
|
+
|
|
114
|
+
const androidPackage = cfg.android?.package
|
|
115
|
+
if (!androidPackage) return cfg
|
|
116
|
+
|
|
117
|
+
// Most Expo + FCM consumers omit android.googleServicesFile and rely on
|
|
118
|
+
// the default ./google-services.json at the project root. Mirror that
|
|
119
|
+
// default (and `acoustic-connect doctor`'s) so the match check isn't
|
|
120
|
+
// silently skipped for the common case.
|
|
121
|
+
const gsFile = cfg.android?.googleServicesFile ?? 'google-services.json'
|
|
122
|
+
const gsPath = path.isAbsolute(gsFile)
|
|
123
|
+
? gsFile
|
|
124
|
+
: path.join(projectRoot, gsFile)
|
|
125
|
+
if (!fs.existsSync(gsPath)) return cfg // missing file is doctor's / the build's concern
|
|
126
|
+
|
|
127
|
+
let parsed: {
|
|
128
|
+
client?: Array<{
|
|
129
|
+
client_info?: { android_client_info?: { package_name?: string } }
|
|
130
|
+
}>
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
parsed = JSON.parse(fs.readFileSync(gsPath, 'utf8'))
|
|
134
|
+
} catch {
|
|
135
|
+
return cfg // malformed google-services.json — doctor/build will report it
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const packages = (parsed.client ?? [])
|
|
139
|
+
.map((c) => c.client_info?.android_client_info?.package_name)
|
|
140
|
+
.filter((p): p is string => typeof p === 'string')
|
|
141
|
+
|
|
142
|
+
if (packages.length > 0 && !packages.includes(androidPackage)) {
|
|
143
|
+
throw new Error(
|
|
144
|
+
`[react-native-acoustic-connect-beta] android.package "${androidPackage}" ` +
|
|
145
|
+
`has no matching client in ${gsFile} (it has: ${packages.join(', ')}).\n\n` +
|
|
146
|
+
`FCM matches its client by package name, so the Android build would ` +
|
|
147
|
+
`fail at :app:processDebugGoogleServices. Register "${androidPackage}" in ` +
|
|
148
|
+
`the same Firebase project and re-download google-services.json, or set ` +
|
|
149
|
+
`app.json android.package to one of the registered packages.\n` +
|
|
150
|
+
`Note: changing android.package requires a clean prebuild — ` +
|
|
151
|
+
`\`npx expo prebuild --platform android --clean\`.`
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
return cfg
|
|
155
|
+
},
|
|
156
|
+
])
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// Copyright (C) 2026 Acoustic, L.P. All rights reserved.
|
|
2
|
+
//
|
|
3
|
+
// NOTICE: This file contains material that is confidential and proprietary to
|
|
4
|
+
// Acoustic, L.P. and/or other developers. No license is granted under any
|
|
5
|
+
// intellectual or industrial property rights of Acoustic, L.P. except as may
|
|
6
|
+
// be provided in an agreement with Acoustic, L.P. Any unauthorized copying or
|
|
7
|
+
// distribution of content from this file is prohibited.
|
|
8
|
+
|
|
9
|
+
import { withXcodeProject, type ConfigPlugin } from '@expo/config-plugins'
|
|
10
|
+
import type { ExpoConfig } from '@expo/config-types'
|
|
11
|
+
import * as fs from 'fs'
|
|
12
|
+
import * as path from 'path'
|
|
13
|
+
|
|
14
|
+
import type { ConnectPluginProps } from './withConnectNSE'
|
|
15
|
+
|
|
16
|
+
// Derive the xcode project type from the callback (the `xcode` package ships no
|
|
17
|
+
// types of its own) — same approach as withConnectNSE.
|
|
18
|
+
type XcodeProject = Parameters<
|
|
19
|
+
Parameters<typeof withXcodeProject>[1]
|
|
20
|
+
>[0]['modResults']
|
|
21
|
+
|
|
22
|
+
const PLACEHOLDER_TEAM = 'YOUR_TEAM_ID'
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Resolves the iOS signing team (Apple Team ID) for the host + push extensions.
|
|
26
|
+
*
|
|
27
|
+
* Priority:
|
|
28
|
+
* 1. `iosDevelopmentTeam` plugin prop in app.json (explicit override)
|
|
29
|
+
* 2. `Connect.iOSDevelopmentTeam` in `<projectRoot>/ConnectConfig.json`
|
|
30
|
+
*
|
|
31
|
+
* Returns `undefined` when neither source provides a real value (the placeholder
|
|
32
|
+
* `YOUR_TEAM_ID` counts as unset). The mod is then a no-op — never a regression.
|
|
33
|
+
*/
|
|
34
|
+
export function resolveDevelopmentTeam(
|
|
35
|
+
projectRoot: string,
|
|
36
|
+
props: ConnectPluginProps
|
|
37
|
+
): string | undefined {
|
|
38
|
+
const fromProp = props.iosDevelopmentTeam?.trim()
|
|
39
|
+
if (fromProp && fromProp !== PLACEHOLDER_TEAM) return fromProp
|
|
40
|
+
|
|
41
|
+
const configPath = path.join(projectRoot, 'ConnectConfig.json')
|
|
42
|
+
if (fs.existsSync(configPath)) {
|
|
43
|
+
try {
|
|
44
|
+
const parsed = JSON.parse(fs.readFileSync(configPath, 'utf8')) as {
|
|
45
|
+
Connect?: { iOSDevelopmentTeam?: unknown }
|
|
46
|
+
}
|
|
47
|
+
const team = parsed.Connect?.iOSDevelopmentTeam
|
|
48
|
+
if (typeof team === 'string' && team.trim() && team.trim() !== PLACEHOLDER_TEAM)
|
|
49
|
+
return team.trim()
|
|
50
|
+
} catch {
|
|
51
|
+
// Malformed JSON is already surfaced by resolveAppGroupIdentifier (which
|
|
52
|
+
// runs earlier in the NSE mod) — don't double-report here.
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return undefined
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Expo Config Plugin mod that stamps `DEVELOPMENT_TEAM` onto every target's
|
|
60
|
+
* build configuration in the generated Xcode project (host + ConnectNSE +
|
|
61
|
+
* ConnectNCE), so all three sign consistently.
|
|
62
|
+
*
|
|
63
|
+
* Why this matters: the NSE mod injects the `aps-environment` entitlement, but
|
|
64
|
+
* a CLI build (`expo run:ios` / `xcodebuild`) with no signing team falls back
|
|
65
|
+
* to ad-hoc signing (`CODE_SIGN_IDENTITY = -`), which DROPS that entitlement —
|
|
66
|
+
* so the OS issues no APNs token and push silently fails (CA-144135 §6). Setting
|
|
67
|
+
* the team closes that loop on the prebuild path the SDK owns. Provisioning
|
|
68
|
+
* itself still needs the developer's Apple ID in Xcode and
|
|
69
|
+
* `-allowProvisioningUpdates` on the build (documented in the README).
|
|
70
|
+
*
|
|
71
|
+
* No-op when no team is configured (no regression for consumers who sign in the
|
|
72
|
+
* Xcode GUI or via EAS, which manages the whole chain itself).
|
|
73
|
+
*
|
|
74
|
+
* Must run AFTER withConnectNSE / withConnectNCE so the extension targets exist.
|
|
75
|
+
*/
|
|
76
|
+
export const withConnectIosSigning: ConfigPlugin<ConnectPluginProps> = (
|
|
77
|
+
config,
|
|
78
|
+
props = {}
|
|
79
|
+
) => {
|
|
80
|
+
const projectRoot = config._internal?.projectRoot
|
|
81
|
+
// withConnectNSE already throws an actionable error when projectRoot is
|
|
82
|
+
// missing; here we simply skip so we never throw twice for the same cause.
|
|
83
|
+
if (!projectRoot) return config
|
|
84
|
+
|
|
85
|
+
const team = resolveDevelopmentTeam(projectRoot, props)
|
|
86
|
+
if (!team) return config
|
|
87
|
+
|
|
88
|
+
return withXcodeProject(config, (c) => {
|
|
89
|
+
const xcodeProject: XcodeProject = c.modResults
|
|
90
|
+
const configurations = xcodeProject.pbxXCBuildConfigurationSection() as Record<
|
|
91
|
+
string,
|
|
92
|
+
{ buildSettings?: Record<string, string | undefined> }
|
|
93
|
+
>
|
|
94
|
+
// Set the team on every build configuration that has a buildSettings block
|
|
95
|
+
// (host + both extensions). Project-level configs get it too, which is
|
|
96
|
+
// harmless and ensures consistency across all targets.
|
|
97
|
+
for (const key of Object.keys(configurations)) {
|
|
98
|
+
const entry = configurations[key]
|
|
99
|
+
if (entry && typeof entry === 'object' && entry.buildSettings) {
|
|
100
|
+
entry.buildSettings.DEVELOPMENT_TEAM = team
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return c
|
|
104
|
+
}) as ExpoConfig
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export default withConnectIosSigning
|
|
@@ -28,6 +28,13 @@ import * as path from 'path'
|
|
|
28
28
|
export interface ConnectPluginProps {
|
|
29
29
|
/** Explicit App Group override. Wins over ConnectConfig.json when set. */
|
|
30
30
|
iosAppGroupIdentifier?: string
|
|
31
|
+
/**
|
|
32
|
+
* Apple Team ID (10-char) used to sign the host app and the push extensions.
|
|
33
|
+
* Wins over `Connect.iOSDevelopmentTeam` in ConnectConfig.json when set.
|
|
34
|
+
* Required for push: without a team, a CLI build drops the `aps-environment`
|
|
35
|
+
* entitlement to ad-hoc signing and the OS issues no APNs token.
|
|
36
|
+
*/
|
|
37
|
+
iosDevelopmentTeam?: string
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
// ─── App Group resolution ─────────────────────────────────────────────────────
|