Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add mani #3209

Merged
merged 17 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions mani/.expo-shared/assets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true,
"40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true
}
31 changes: 31 additions & 0 deletions mani/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
node_modules/
.expo/
dist/
npm-debug.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
*.orig.*
web-build/
credentials.json
credentials/
*.apk
*.aab
*.ipa
project.pbxproj
ios/Manifold/GoogleService-Info.plist
ios/Manifold.xcodeproj/project.pbxproj
/google-services.json
# macOS
.DS_Store
# simulator build
*.tar.gz
.env.local

# @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb
# The following patterns were generated by expo-cli

expo-env.d.ts
# @end expo-cli
128 changes: 128 additions & 0 deletions mani/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
We're using Expo to help with android and ios builds. You can find more information about Expo here: https://docs.expo.dev/introduction/expo/

## Installing

- The `native/` directory is not part of the yarn workspace, so you have to run `yarn` in the `native/` directory to install dependencies.
- You will need to install the Expo CLI globally: `npm install -g expo-cli`
- You need to set the `SENTRY_AUTH_TOKEN` via `eas:secret` [link](https://docs.expo.dev/build-reference/variables/#using-secrets-in-environment-variables)
- You need to make sure the Manifold Markets, Inc. team is set as the signer for app builds in Xcode - open up ios directory in Xcode and set the signing account.
- You need to register your device for development builds with Expo and install a provisioning profile, see the [Running a build](https://docs.expo.dev/development/build/) section with `eas device:create`

## Configuration

- `app.json` and `app.config.js` are the configuration files that determine basic functioning of the app. If you change them you'll have to clean your `android` and `ios` folders via `yarn clean`

## Developing

1. Connect your phone to your computer
2. **iOS**:
- `yarn build:ios:client:prod` or `yarn build:ios:client:dev` to build a dev client and drag it onto your iPhone to install it.
- `yarn start` or `yarn start:dev` and scan the QR code with camera
- Keep a dev client build in the native directory so you can just drag and drop them onto your phone to install them
3. **Android**:
- `yarn android:dev` or `yarn android:prod` builds and installs the dev client on your device automatically
- Scan the QR code with the app (it opens automatically after installing)
4. **Locally hosted manifold**:
- Set the `NEXT_PUBLIC_API_URL` in dev.sh to your local ip address
- Run `dev.sh prod` or `dev.sh dev` to start the local server
- Change the `baseUri` in `App.tsx` to your local ip address
- Follow one of the Android or iOS steps to start the app on your device

- **Note:** when switching between dev and prod you'll have to run `yarn clear` & Ctrl+C to clear the env variable.
- Want to see console logs? (Only works on android):
- Set the `NEXT_PUBLIC_API_URL` in dev.sh to your local ip address
- Change the `baseUri` in `App.tsx` to your local ip address
- `$ yarn android:prod` to start the app on your device
- On your computer, navigate to `chrome://inspect/#devices` in chrome and click inspect on the app
- Want to see app logs of a production build? (Only works on android):
- `$ adb logcat --pid=$(adb shell pidof -s com.markets.manifold)`

## Building

- You'll need to get Android signing credentials from Ian (located [here](https://drive.google.com/drive/folders/155gaiY97oY0IkQvHGKHqKbXEeO4LaVCe?usp=sharing)) to properly sign android builds for the google play store. You'll probably need to be added to the Apple Business developer team when we get that to build ios apps.
- After changing anything in the `app.config.js` or `app.json` you'll want to run `npx expo prebuild` to clear the android and ios folders
- Before every build we clean and reset the git tree so you'll want to make sure any changes are committed. The dialog will ask you to confirm this.
- After every build your git tree may be dirty with build artifacts. I tried removing these and ended up down in a git-sponsored nightmare, so I wouldn't advise trying to edit these files out of the git history unless you really know what you're doing.
- The following commands build the binaries locally by default. If you remove the `--local` flag it will build in the EAS/Expo cloud, (this tends to be much slower, though).
- Before every submission to the app store you'll want to bump the following fields in `app.json`:
- `expo.version`
- `expo.ios.buildNumber`
- `expo.android.versionCode`

**For Internal Testing**
`yarn build:android:preview`

- Builds an Android APK for previewing on a device
- `adb install build_name_here.apk` after it's built to install

`yarn build:ios:prod`

- Builds an iOS IPA that you can upload to TestFlight

`yarn build:ios:preview`

- Builds an iOS IPA for previewing on a device
- Drag and drop onto your plugged in iPhone Finder window to install

**External**
`yarn build:android:prod`

- Builds an Android App Bundle for Google Play distribution
- Upload to Google Play Console

`yarn build:ios:prod`

- Builds an iOS IPA for App Store distribution
- I think we use Transporter once we have our Apple Business Developer account set up

### OTA updates

`eas update --branch default` to publish an over-the-air update to production

### Adding Environment Variables

- Set the variable in `package.json` (used for local development aka `yarn ios:prod`)
- Add the key-value pair to the `extra.eas` object in `app.config.js` with value `process.env.YOUR_ENV_VARIABLE`
- Set the build variable in `eas.json` for the profile you want (used for eas builds aka `yarn build:ios:prod`)
- Reference it in js: `Constants.expoConfig?.extra?.eas.YOUR_ENV_VARIABLE`
- Run `yarn clear` to clear the env variable between builds

# Icons

find icons [here](https://icons.expo.fyi/)

## Notes

- The dev and prod version of the app use the same application id (`com.markets.manifold`). This may not be not ideal but it works.
- Notifications on android dev I think won't work bc we have to use Firebase's server signing key to send push notifications and I just linked our application id (com.markets.manifold) to the prod server signing key. To fix I'd have to have a separate application id for dev, which I could do but you can just test on prod
- Try out sending push notifications [here](https://expo.dev/notifications) (using the `pushToken` from your `private-user` object)
- Google play release console [here](https://play.google.com/console/u/1/developers/4817631028794628961/app/4973740210331758857/releases/overview)

## Monitoring

- [Sentry](https://sentry.io/organizations/manifold-markets/projects/react-native/?issuesType=new&project=4504040585494528)

## Updating Expo

- Check out the [helper guide](https://docs.expo.dev/bare/upgrade/?fromSdk=50&toSdk=51)

### Problems with building android after deleting `android/`

- `However we cannot choose between the following variants of project :react-native-iap: - amazonDebugRuntimeElements - playDebugRuntimeElements`
- Add `missingDimensionStrategy 'store', 'play'` to `android/app/build.gradle` in the `defaultConfig` section
- `error: cannot find symbol import com.markets.BuildConfig;`
- Add `namespace "com.markets.manifold"` in place of `namespace "com.manifold"` to `app/build.gradle`
- Add `package com.markets.manifold;` in place of incorrect package at the top of `native/android/app/src/release/java/com/manifold/ReactNativeFlipper.java`

## Troubleshooting

- getting an errors on build/install? like `Error: spawn .../manifold/native/android/gradlew EACCES`
- Delete the `android` or `ios` folders or run `yarn clean` and try again.
- environment variables not working? like `process.env.API_URL` is undefined
- Try running `yarn clear` and ctrl+c to clear the env variable and try again
- When in doubt: `yarn clean`
- Fastlane build failing? Could be a malformed import
- Pod install erroring out?
- I had to reinstall cocoapods via [these instructions](https://github.com/expo/expo/issues/20707#issuecomment-1377790160)
- Sentry problems? `sentry.properties` file not found or malformed?
- `eas build` couldn't find the sentry.properties file in the `android` directory generated from `eas.json`, so I set its path in eas.json to the root. If it's malformed, check the diff from the ones in the `ios` and `android` directories which are autogenerated from `eas.json`.
16 changes: 16 additions & 0 deletions mani/Supporting/Expo.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>EXUpdatesCheckOnLaunch</key>
<string>ALWAYS</string>
<key>EXUpdatesEnabled</key>
<true/>
<key>EXUpdatesLaunchWaitMs</key>
<integer>0</integer>
<key>EXUpdatesSDKVersion</key>
<string>46.0.0</string>
<key>EXUpdatesURL</key>
<string>https://exp.host/@my-expo-username/my-app</string>
</dict>
</plist>
16 changes: 16 additions & 0 deletions mani/android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# OSX
#
.DS_Store

# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
*.hprof
.cxx/

# Bundle artifacts
*.jsbundle
180 changes: 180 additions & 0 deletions mani/android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
apply plugin: "com.android.application"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"

def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath()

/**
* This is the configuration block to customize your React Native Android app.
* By default you don't need to apply any configuration, just uncomment the lines you need.
*/
react {
entryFile = file(["node", "-e", "require('expo/scripts/resolveAppEntry')", projectRoot, "android", "absolute"].execute(null, rootDir).text.trim())
reactNativeDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc"
codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()

// Use Expo CLI to bundle the app, this ensures the Metro config
// works correctly with Expo projects.
cliFile = new File(["node", "--print", "require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })"].execute(null, rootDir).text.trim())
bundleCommand = "export:embed"

/* Folders */
// The root of your project, i.e. where "package.json" lives. Default is '../..'
// root = file("../../")
// The folder where the react-native NPM package is. Default is ../../node_modules/react-native
// reactNativeDir = file("../../node_modules/react-native")
// The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
// codegenDir = file("../../node_modules/@react-native/codegen")

/* Variants */
// The list of variants to that are debuggable. For those we're going to
// skip the bundling of the JS bundle and the assets. By default is just 'debug'.
// If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
// debuggableVariants = ["liteDebug", "prodDebug"]

/* Bundling */
// A list containing the node command and its flags. Default is just 'node'.
// nodeExecutableAndArgs = ["node"]

//
// The path to the CLI configuration file. Default is empty.
// bundleConfig = file(../rn-cli.config.js)
//
// The name of the generated asset file containing your JS bundle
// bundleAssetName = "MyApplication.android.bundle"
//
// The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
// entryFile = file("../js/MyApplication.android.js")
//
// A list of extra flags to pass to the 'bundle' commands.
// See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
// extraPackagerArgs = []

/* Hermes Commands */
// The hermes compiler command to run. By default it is 'hermesc'
// hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
//
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
// hermesFlags = ["-O", "-output-source-map"]

/* Autolinking */
autolinkLibrariesWithApp()
}

/**
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
*/
def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInReleaseBuilds') ?: false).toBoolean()

/**
* The preferred build flavor of JavaScriptCore (JSC)
*
* For example, to use the international variant, you can use:
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
*
* The international variant includes ICU i18n library and necessary data
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
* give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default.
*/
def jscFlavor = 'org.webkit:android-jsc:+'

apply from: new File(["node", "--print", "require('path').dirname(require.resolve('@sentry/react-native/package.json'))"].execute().text.trim(), "sentry.gradle")

android {
ndkVersion rootProject.ext.ndkVersion

buildToolsVersion rootProject.ext.buildToolsVersion
compileSdk rootProject.ext.compileSdkVersion

namespace 'com.manifold.mani'
defaultConfig {
applicationId 'com.manifold.mani'
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 62
versionName "2.0.54"
}
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
// Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.debug
shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
}
}
packagingOptions {
jniLibs {
useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false)
}
}
androidResources {
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~'
}
}

// Apply static values from `gradle.properties` to the `android.packagingOptions`
// Accepts values in comma delimited lists, example:
// android.packagingOptions.pickFirsts=/LICENSE,**/picasa.ini
["pickFirsts", "excludes", "merges", "doNotStrip"].each { prop ->
// Split option: 'foo,bar' -> ['foo', 'bar']
def options = (findProperty("android.packagingOptions.$prop") ?: "").split(",");
// Trim all elements in place.
for (i in 0..<options.size()) options[i] = options[i].trim();
// `[] - ""` is essentially `[""].filter(Boolean)` removing all empty strings.
options -= ""

if (options.length > 0) {
println "android.packagingOptions.$prop += $options ($options.length)"
// Ex: android.packagingOptions.pickFirsts += '**/SCCS/**'
options.each {
android.packagingOptions[prop] += it
}
}
}

dependencies {
// The version of react-native is set by the React Native Gradle Plugin
implementation("com.facebook.react:react-android")

def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true";

if (isGifEnabled) {
// For animated gif support
implementation("com.facebook.fresco:animated-gif:${reactAndroidLibs.versions.fresco.get()}")
}

if (isWebpEnabled) {
// For webp support
implementation("com.facebook.fresco:webpsupport:${reactAndroidLibs.versions.fresco.get()}")
if (isWebpAnimatedEnabled) {
// Animated webp support
implementation("com.facebook.fresco:animated-webp:${reactAndroidLibs.versions.fresco.get()}")
}
}

if (hermesEnabled.toBoolean()) {
implementation("com.facebook.react:hermes-android")
} else {
implementation jscFlavor
}
}

apply plugin: 'com.google.gms.google-services'
Binary file added mani/android/app/debug.keystore
Binary file not shown.
Loading
Loading