Live video on the AT Protocol
at eli/multitesting 296 lines 8.6 kB view raw
1import { 2 ConfigPlugin, 3 withAndroidManifest, 4 withEntitlementsPlist, 5 withXcodeProject, 6} from "expo/config-plugins"; 7import streamplaceReactNativeWebRTC from "../config-react-native-webrtc"; 8export const withNotificationsIOS: ConfigPlugin = (config) => { 9 config = withEntitlementsPlist(config, (config) => { 10 config.modResults["aps-environment"] = "production"; 11 return config; 12 }); 13 return config; 14}; 15 16export const withoutNotificationsIOS: ConfigPlugin = (config) => { 17 config = withEntitlementsPlist(config, (config) => { 18 delete config.modResults["aps-environment"]; 19 return config; 20 }); 21 return config; 22}; 23 24const withAndroidProfileable = (config) => { 25 return withAndroidManifest(config, (config) => { 26 const androidManifest = config.modResults.manifest; 27 if ( 28 !androidManifest.application || 29 androidManifest.application.length === 0 30 ) { 31 throw new Error("No application found in AndroidManifest.xml"); 32 } 33 const mainApplication = androidManifest.application[0]; 34 35 (mainApplication as any).profileable = [ 36 { 37 $: { 38 "android:shell": "true", 39 "android:enabled": "true", 40 }, 41 }, 42 ]; 43 44 return config; 45 }); 46}; 47 48const withConsistentVersionNumber = ( 49 config, 50 { version }: { version: string }, 51) => { 52 // if (!config.ios) { 53 // config.ios = {}; 54 // } 55 // if (!config.ios.infoPlist) { 56 // config.ios.infoPlist = {}; 57 // } 58 config = withXcodeProject(config, (config) => { 59 for (let [k, v] of Object.entries( 60 config.modResults.hash.project.objects.XCBuildConfiguration, 61 )) { 62 const obj = v as any; 63 if (!obj.buildSettings) { 64 continue; 65 } 66 if (typeof obj.buildSettings.MARKETING_VERSION !== "undefined") { 67 obj.buildSettings.MARKETING_VERSION = version; 68 } 69 if (typeof obj.buildSettings.CURRENT_PROJECT_VERSION !== "undefined") { 70 obj.buildSettings.CURRENT_PROJECT_VERSION = version; 71 } 72 } 73 return config; 74 }); 75 return config; 76}; 77 78// turn a semver string into a always-increasing integer for google 79export const versionCode = (verStr: string) => { 80 const [major, minor, patch] = verStr.split(".").map((x) => parseInt(x)); 81 return major * 1000 * 1000 + minor * 1000 + patch; 82}; 83 84export default function () { 85 const isProd = 86 process.env["SP_PRODUCTION_RELEASE"] === "true" || !!process.env.CI; 87 const enableSentry = process.env["SP_ENABLE_SENTRY"] === "true"; 88 const pkg = require("./package.json"); 89 const name = isProd ? "Streamplace" : "Devplace"; 90 let bundle = isProd ? "tv.aquareum" : "tv.aquareum.dev"; 91 if (process.env["SP_BUNDLE_OVERRIDE"]) { 92 bundle = process.env["SP_BUNDLE_OVERRIDE"]; 93 } 94 let appleTeamId = process.env["SP_APPLE_TEAM_ID"]; 95 const scheme = process.env["SP_APP_SCHEME"] ?? bundle; 96 return { 97 expo: { 98 name: name, 99 slug: name, 100 version: pkg.version, 101 // Only rev this to the current version when native dependencies change! 102 runtimeVersion: pkg.runtimeVersion, 103 orientation: "default", 104 icon: "./assets/images/icon.png", 105 scheme: scheme, 106 userInterfaceStyle: "automatic", 107 splash: { 108 image: "./assets/images/splash.png", 109 resizeMode: "contain", 110 backgroundColor: "#ffffff", 111 }, 112 assetBundlePatterns: ["**/*"], 113 ios: { 114 supportsTablet: true, 115 bundleIdentifier: bundle, 116 infoPlist: { 117 UIBackgroundModes: ["fetch", "remote-notification"], 118 LSMinimumSystemVersion: "12.0", 119 }, 120 ...(appleTeamId 121 ? { 122 appleTeamId, 123 } 124 : {}), 125 ...(isProd 126 ? { 127 googleServicesFile: "./GoogleService-Info.plist", 128 entitlements: { 129 "aps-environment": "production", 130 }, 131 associatedDomains: ["applinks:stream.place"], 132 } 133 : {}), 134 }, 135 android: { 136 adaptiveIcon: { 137 foregroundImage: "./assets/images/adaptive-icon.png", 138 backgroundColor: "#ffffff", 139 }, 140 package: bundle, 141 edgeToEdgeEnabled: true, 142 versionCode: versionCode(pkg.version), 143 intentFilters: [ 144 { 145 action: "VIEW", 146 autoVerify: true, 147 data: [ 148 { 149 scheme: "https", 150 host: "stream.place", 151 pathPattern: "/.*:.*", 152 }, 153 ], 154 category: ["BROWSABLE", "DEFAULT"], 155 }, 156 { 157 action: "VIEW", 158 autoVerify: true, 159 data: [ 160 { 161 scheme: "https", 162 host: "stream.place", 163 pathPattern: "/.*\\\\..*", 164 }, 165 ], 166 category: ["BROWSABLE", "DEFAULT"], 167 }, 168 { 169 action: "VIEW", 170 autoVerify: true, 171 data: [ 172 { 173 scheme: "https", 174 host: "stream.place", 175 path: "/", 176 }, 177 ], 178 category: ["BROWSABLE", "DEFAULT"], 179 }, 180 ], 181 ...(isProd 182 ? { 183 googleServicesFile: "./google-services.json", 184 permissions: [ 185 "android.permission.SCHEDULE_EXACT_ALARM", 186 "android.permission.POST_NOTIFICATIONS", 187 ], 188 } 189 : {}), 190 }, 191 web: { 192 bundler: "metro", 193 output: "single", 194 favicon: "./assets/images/favicon.png", 195 }, 196 plugins: [ 197 withAndroidProfileable, 198 "expo-video", 199 "expo-web-browser", 200 "expo-screen-orientation", 201 streamplaceReactNativeWebRTC, 202 [ 203 "expo-video", 204 { 205 supportsBackgroundPlayback: true, 206 supportsPictureInPicture: true, 207 }, 208 ], 209 ["expo-sqlite", { useSQLCipher: true }], 210 "expo-file-system", 211 [ 212 "expo-font", 213 { 214 fonts: [ 215 "./assets/fonts/AtkinsonHyperlegibleNext-Regular.ttf", 216 "./assets/fonts/AtkinsonHyperlegibleNext-Light.ttf", 217 "./assets/fonts/AtkinsonHyperlegibleNext-ExtraLight.ttf", 218 "./assets/fonts/AtkinsonHyperlegibleNext-Medium.ttf", 219 "./assets/fonts/AtkinsonHyperlegibleNext-SemiBold.ttf", 220 "./assets/fonts/AtkinsonHyperlegibleNext-Bold.ttf", 221 "./assets/fonts/AtkinsonHyperlegibleNext-ExtraBold.ttf", 222 223 "./assets/fonts/AtkinsonHyperlegibleMono-Regular.ttf", 224 "./assets/fonts/AtkinsonHyperlegibleMono-Medium.ttf", 225 "./assets/fonts/AtkinsonHyperlegibleMono-SemiBold.ttf", 226 "./assets/fonts/AtkinsonHyperlegibleMono-Bold.ttf", 227 ], 228 }, 229 ], 230 [ 231 "expo-build-properties", 232 { 233 ios: { 234 useFrameworks: "static", 235 }, 236 // uncomment to test OTA updates to http://localhost:8080 237 // android: { 238 // usesCleartextTraffic: true, 239 // }, 240 }, 241 ], 242 [ 243 "expo-asset", 244 { 245 assets: ["assets"], 246 }, 247 ], 248 [withConsistentVersionNumber, { version: pkg.version }], 249 [ 250 "react-native-edge-to-edge", 251 { 252 android: { 253 parentTheme: "Default", 254 enforceNavigationBarContrast: false, 255 }, 256 }, 257 ], 258 ...(isProd 259 ? [ 260 "@react-native-firebase/app", 261 "@react-native-firebase/messaging", 262 [withNotificationsIOS, {}], 263 ] 264 : ["expo-dev-launcher", withoutNotificationsIOS]), 265 ...(enableSentry 266 ? [ 267 [ 268 "@sentry/react-native/expo", 269 { 270 url: "https://sentry.io/", 271 project: process.env["SP_SENTRY_APP"] || "app", 272 organization: process.env["SP_SENTRY_ORG"] || "streamplace", 273 }, 274 ], 275 ] 276 : []), 277 ], 278 experiments: { 279 typedRoutes: true, 280 }, 281 updates: isProd 282 ? { 283 url: `https://stream.place/api/manifest`, 284 enabled: true, 285 checkAutomatically: "ON_LOAD", 286 fallbackToCacheTimeout: 30000, 287 codeSigningCertificate: "./code-signing/certs/certificate.pem", 288 codeSigningMetadata: { 289 keyid: "main", 290 alg: "rsa-v1_5-sha256", 291 }, 292 } 293 : {}, 294 }, 295 }; 296}