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