forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1// @ts-check
2const pkg = require('./package.json')
3
4/**
5 * @param {import('@expo/config-types').ExpoConfig} _config
6 * @returns {{ expo: import('@expo/config-types').ExpoConfig }}
7 */
8module.exports = function (_config) {
9 /**
10 * App version number. Should be incremented as part of a release cycle.
11 */
12 const VERSION = pkg.version
13
14 /**
15 * Uses built-in Expo env vars
16 *
17 * @see https://docs.expo.dev/build-reference/variables/#built-in-environment-variables
18 */
19 const PLATFORM = process.env.EAS_BUILD_PLATFORM ?? 'web'
20
21 const IS_TESTFLIGHT = process.env.EXPO_PUBLIC_ENV === 'testflight'
22 const IS_PRODUCTION = process.env.EXPO_PUBLIC_ENV === 'production'
23 const IS_DEV = !IS_TESTFLIGHT && !IS_PRODUCTION
24
25 const ASSOCIATED_DOMAINS = [
26 'applinks:bsky.app',
27 'applinks:staging.bsky.app',
28 'appclips:bsky.app',
29 'appclips:go.bsky.app', // Allows App Clip to work when scanning QR codes
30 // When testing local services, enter an ngrok (et al) domain here. It must use a standard HTTP/HTTPS port.
31 ...(IS_DEV || IS_TESTFLIGHT ? [] : []),
32 ]
33
34 const UPDATES_ENABLED = IS_TESTFLIGHT || IS_PRODUCTION
35
36 const USE_SENTRY = Boolean(process.env.SENTRY_AUTH_TOKEN)
37
38 return {
39 expo: {
40 version: VERSION,
41 name: 'Bluesky',
42 slug: 'bluesky',
43 scheme: 'bluesky',
44 owner: 'blueskysocial',
45 runtimeVersion: {
46 policy: 'appVersion',
47 },
48 icon: './assets/app-icons/ios_icon_default_next.png',
49 userInterfaceStyle: 'automatic',
50 primaryColor: '#1083fe',
51 newArchEnabled: false,
52 ios: {
53 supportsTablet: false,
54 bundleIdentifier: 'xyz.blueskyweb.app',
55 config: {
56 usesNonExemptEncryption: false,
57 },
58 icon:
59 PLATFORM === 'web' // web build doesn't like .icon files
60 ? './assets/app-icons/ios_icon_default_next.png'
61 : './assets/app-icons/ios_icon_default.icon',
62 infoPlist: {
63 UIBackgroundModes: ['remote-notification'],
64 NSCameraUsageDescription:
65 'Used for profile pictures, posts, and other kinds of content.',
66 NSMicrophoneUsageDescription:
67 'Used for posts and other kinds of content.',
68 NSPhotoLibraryAddUsageDescription:
69 'Used to save images to your library.',
70 NSPhotoLibraryUsageDescription:
71 'Used for profile pictures, posts, and other kinds of content',
72 CFBundleSpokenName: 'Blue Sky',
73 CFBundleLocalizations: [
74 'en',
75 'an',
76 'ast',
77 'ca',
78 'cy',
79 'da',
80 'de',
81 'el',
82 'eo',
83 'es',
84 'eu',
85 'fi',
86 'fr',
87 'fy',
88 'ga',
89 'gd',
90 'gl',
91 'hi',
92 'hu',
93 'ia',
94 'id',
95 'it',
96 'ja',
97 'km',
98 'ko',
99 'ne',
100 'nl',
101 'pl',
102 'pt-BR',
103 'pt-PT',
104 'ro',
105 'ru',
106 'sv',
107 'th',
108 'tr',
109 'uk',
110 'vi',
111 'yue',
112 'zh-Hans',
113 'zh-Hant',
114 ],
115 UIDesignRequiresCompatibility: true,
116 },
117 associatedDomains: ASSOCIATED_DOMAINS,
118 entitlements: {
119 'com.apple.developer.kernel.increased-memory-limit': true,
120 'com.apple.developer.kernel.extended-virtual-addressing': true,
121 'com.apple.security.application-groups': 'group.app.bsky',
122 // 'com.apple.developer.device-information.user-assigned-device-name': true,
123 },
124 privacyManifests: {
125 NSPrivacyCollectedDataTypes: [
126 {
127 NSPrivacyCollectedDataType: 'NSPrivacyCollectedDataTypeCrashData',
128 NSPrivacyCollectedDataTypeLinked: false,
129 NSPrivacyCollectedDataTypeTracking: false,
130 NSPrivacyCollectedDataTypePurposes: [
131 'NSPrivacyCollectedDataTypePurposeAppFunctionality',
132 ],
133 },
134 {
135 NSPrivacyCollectedDataType:
136 'NSPrivacyCollectedDataTypePerformanceData',
137 NSPrivacyCollectedDataTypeLinked: false,
138 NSPrivacyCollectedDataTypeTracking: false,
139 NSPrivacyCollectedDataTypePurposes: [
140 'NSPrivacyCollectedDataTypePurposeAppFunctionality',
141 ],
142 },
143 {
144 NSPrivacyCollectedDataType:
145 'NSPrivacyCollectedDataTypeOtherDiagnosticData',
146 NSPrivacyCollectedDataTypeLinked: false,
147 NSPrivacyCollectedDataTypeTracking: false,
148 NSPrivacyCollectedDataTypePurposes: [
149 'NSPrivacyCollectedDataTypePurposeAppFunctionality',
150 ],
151 },
152 ],
153 NSPrivacyAccessedAPITypes: [
154 {
155 NSPrivacyAccessedAPIType:
156 'NSPrivacyAccessedAPICategoryFileTimestamp',
157 NSPrivacyAccessedAPITypeReasons: ['C617.1', '3B52.1', '0A2A.1'],
158 },
159 {
160 NSPrivacyAccessedAPIType: 'NSPrivacyAccessedAPICategoryDiskSpace',
161 NSPrivacyAccessedAPITypeReasons: ['E174.1', '85F4.1'],
162 },
163 {
164 NSPrivacyAccessedAPIType:
165 'NSPrivacyAccessedAPICategorySystemBootTime',
166 NSPrivacyAccessedAPITypeReasons: ['35F9.1'],
167 },
168 {
169 NSPrivacyAccessedAPIType:
170 'NSPrivacyAccessedAPICategoryUserDefaults',
171 NSPrivacyAccessedAPITypeReasons: ['CA92.1', '1C8F.1'],
172 },
173 ],
174 },
175 },
176 androidStatusBar: {
177 barStyle: 'light-content',
178 },
179 // Dark nav bar in light mode is better than light nav bar in dark mode
180 androidNavigationBar: {
181 barStyle: 'light-content',
182 },
183 android: {
184 icon: './assets/app-icons/android_icon_default_next.png',
185 adaptiveIcon: {
186 foregroundImage: './assets/icon-android-foreground.png',
187 monochromeImage: './assets/icon-android-monochrome.png',
188 backgroundColor: '#006AFF',
189 },
190 googleServicesFile: './google-services.json',
191 package: 'xyz.blueskyweb.app',
192 intentFilters: [
193 {
194 action: 'VIEW',
195 autoVerify: true,
196 data: [
197 {
198 scheme: 'https',
199 host: 'bsky.app',
200 },
201 ...(IS_DEV
202 ? [
203 {
204 scheme: 'http',
205 host: 'localhost:19006',
206 },
207 ]
208 : []),
209 ],
210 category: ['BROWSABLE', 'DEFAULT'],
211 },
212 ],
213 },
214 web: {
215 favicon: './assets/favicon.png',
216 },
217 updates: {
218 url: 'https://updates.bsky.app/manifest',
219 enabled: UPDATES_ENABLED,
220 fallbackToCacheTimeout: 30000,
221 codeSigningCertificate: UPDATES_ENABLED
222 ? './code-signing/certificate.pem'
223 : undefined,
224 codeSigningMetadata: UPDATES_ENABLED
225 ? {
226 keyid: 'main',
227 alg: 'rsa-v1_5-sha256',
228 }
229 : undefined,
230 checkAutomatically: 'NEVER',
231 },
232 plugins: [
233 'expo-video',
234 'expo-localization',
235 'expo-web-browser',
236 [
237 'react-native-edge-to-edge',
238 {android: {enforceNavigationBarContrast: false}},
239 ],
240 ...(USE_SENTRY
241 ? [
242 /** @type {[string, any]} */ ([
243 '@sentry/react-native/expo',
244 {
245 organization: 'blueskyweb',
246 project: 'app',
247 url: 'https://sentry.io',
248 },
249 ]),
250 ]
251 : []),
252 [
253 'expo-build-properties',
254 {
255 ios: {
256 deploymentTarget: '15.1',
257 buildReactNativeFromSource: true,
258 ccacheEnabled: IS_DEV,
259 },
260 android: {
261 compileSdkVersion: 35,
262 targetSdkVersion: 35,
263 buildToolsVersion: '35.0.0',
264 buildReactNativeFromSource: IS_PRODUCTION,
265 },
266 },
267 ],
268 [
269 'expo-notifications',
270 {
271 icon: './assets/icon-android-notification.png',
272 color: '#1185fe',
273 sounds: PLATFORM === 'ios' ? ['assets/dm.aiff'] : ['assets/dm.mp3'],
274 },
275 ],
276 'react-native-compressor',
277 [
278 '@bitdrift/react-native',
279 {
280 networkInstrumentation: true,
281 },
282 ],
283 './plugins/starterPackAppClipExtension/withStarterPackAppClip.js',
284 './plugins/withGradleJVMHeapSizeIncrease.js',
285 './plugins/withAndroidManifestLargeHeapPlugin.js',
286 './plugins/withAndroidManifestFCMIconPlugin.js',
287 './plugins/withAndroidManifestIntentQueriesPlugin.js',
288 './plugins/withAndroidStylesAccentColorPlugin.js',
289 './plugins/withAndroidDayNightThemePlugin.js',
290 './plugins/withAndroidNoJitpackPlugin.js',
291 './plugins/shareExtension/withShareExtensions.js',
292 './plugins/notificationsExtension/withNotificationsExtension.js',
293 [
294 'expo-font',
295 {
296 fonts: [
297 './assets/fonts/inter/InterVariable.woff2',
298 './assets/fonts/inter/InterVariable-Italic.woff2',
299 // Android only
300 './assets/fonts/inter/Inter-Regular.otf',
301 './assets/fonts/inter/Inter-Italic.otf',
302 './assets/fonts/inter/Inter-Medium.otf',
303 './assets/fonts/inter/Inter-MediumItalic.otf',
304 './assets/fonts/inter/Inter-SemiBold.otf',
305 './assets/fonts/inter/Inter-SemiBoldItalic.otf',
306 './assets/fonts/inter/Inter-Bold.otf',
307 './assets/fonts/inter/Inter-BoldItalic.otf',
308 ],
309 },
310 ],
311 [
312 'expo-splash-screen',
313 {
314 ios: {
315 enableFullScreenImage_legacy: true, // iOS only
316 backgroundColor: '#006AFF', // primary_500
317 image: './assets/splash/splash.png',
318 resizeMode: 'cover',
319 dark: {
320 enableFullScreenImage_legacy: true, // iOS only
321 backgroundColor: '#002861', // primary_900
322 image: './assets/splash/splash-dark.png',
323 resizeMode: 'cover',
324 },
325 },
326 android: {
327 backgroundColor: '#006AFF', // primary_500
328 image: './assets/splash/android-splash-logo-white.png',
329 imageWidth: 102, // even division of 306px
330 dark: {
331 backgroundColor: '#002861', // primary_900
332 image: './assets/splash/android-splash-logo-white.png',
333 imageWidth: 102,
334 },
335 },
336 },
337 ],
338 [
339 '@mozzius/expo-dynamic-app-icon',
340 {
341 /**
342 * Default set
343 */
344 default_light: {
345 ios: './assets/app-icons/ios_icon_legacy_light.png',
346 android: './assets/app-icons/android_icon_legacy_light.png',
347 prerendered: true,
348 },
349 default_dark: {
350 ios: './assets/app-icons/ios_icon_legacy_dark.png',
351 android: './assets/app-icons/android_icon_legacy_dark.png',
352 prerendered: true,
353 },
354
355 /**
356 * Bluesky+ core set
357 */
358 core_aurora: {
359 ios: './assets/app-icons/ios_icon_core_aurora.png',
360 android: './assets/app-icons/android_icon_core_aurora.png',
361 prerendered: true,
362 },
363 core_bonfire: {
364 ios: './assets/app-icons/ios_icon_core_bonfire.png',
365 android: './assets/app-icons/android_icon_core_bonfire.png',
366 prerendered: true,
367 },
368 core_sunrise: {
369 ios: './assets/app-icons/ios_icon_core_sunrise.png',
370 android: './assets/app-icons/android_icon_core_sunrise.png',
371 prerendered: true,
372 },
373 core_sunset: {
374 ios: './assets/app-icons/ios_icon_core_sunset.png',
375 android: './assets/app-icons/android_icon_core_sunset.png',
376 prerendered: true,
377 },
378 core_midnight: {
379 ios: './assets/app-icons/ios_icon_core_midnight.png',
380 android: './assets/app-icons/android_icon_core_midnight.png',
381 prerendered: true,
382 },
383 core_flat_blue: {
384 ios: './assets/app-icons/ios_icon_core_flat_blue.png',
385 android: './assets/app-icons/android_icon_core_flat_blue.png',
386 prerendered: true,
387 },
388 core_flat_white: {
389 ios: './assets/app-icons/ios_icon_core_flat_white.png',
390 android: './assets/app-icons/android_icon_core_flat_white.png',
391 prerendered: true,
392 },
393 core_flat_black: {
394 ios: './assets/app-icons/ios_icon_core_flat_black.png',
395 android: './assets/app-icons/android_icon_core_flat_black.png',
396 prerendered: true,
397 },
398 core_classic: {
399 ios: './assets/app-icons/ios_icon_core_classic.png',
400 android: './assets/app-icons/android_icon_core_classic.png',
401 prerendered: true,
402 },
403 },
404 ],
405 ['expo-screen-orientation', {initialOrientation: 'PORTRAIT_UP'}],
406 ['expo-location'],
407 [
408 'expo-contacts',
409 {
410 contactsPermission:
411 'I agree to allow Bluesky to use my contacts for friend discovery until I opt out.',
412 },
413 ],
414 ],
415 extra: {
416 eas: {
417 build: {
418 experimental: {
419 ios: {
420 appExtensions: [
421 {
422 targetName: 'Share-with-Bluesky',
423 bundleIdentifier: 'xyz.blueskyweb.app.Share-with-Bluesky',
424 entitlements: {
425 'com.apple.security.application-groups': [
426 'group.app.bsky',
427 ],
428 },
429 },
430 {
431 targetName: 'BlueskyNSE',
432 bundleIdentifier: 'xyz.blueskyweb.app.BlueskyNSE',
433 entitlements: {
434 'com.apple.security.application-groups': [
435 'group.app.bsky',
436 ],
437 },
438 },
439 {
440 targetName: 'BlueskyClip',
441 bundleIdentifier: 'xyz.blueskyweb.app.AppClip',
442 },
443 ],
444 },
445 },
446 },
447 projectId: '55bd077a-d905-4184-9c7f-94789ba0f302',
448 },
449 },
450 },
451 }
452}