Use turtle to build standalone apps on local machine and for Continuous Integration (CI) setups
tl;dr
ngrok http 127.0.0.1:8080 -host-header="127.0.0.1:8080"
rm -rf dist/ && expo export --public-url https://XXXXXXXXXXXX.ngrok.io
cd dist/ && npx http-server
and confirm it’s running curl https://XXXXXXXXXXXX.ngrok.io/android-index.json
turtle-cli
with --public-url
pointing to the secure server1EXPO_ANDROID_KEYSTORE_PASSWORD="XXXXXXXX" \
2EXPO_ANDROID_KEY_PASSWORD="XXXXXXXX" \
3turtle build:android \
4 --keystore-path /PATH/TO/YOUR/KEYSTORE_FILE.jks \
5 --keystore-alias PUT_KEYSTORE_ALIAS_HERE
6 --public-url https://XXXXXXXXXXXX.ngrok.io/android-index.json
Right now when you run the expo build command, it puts you into a queue, and stores the build on Expo servers. I obviously don’t want that because a queue slows me down (the build keeps failing..) and once the build is done i have to manually download it in order to be able to upload it somewhere else..
The answer to this is turtle, the standalone app builder service by Expo
1npm install -g turtle-cli
2
3turtle setup:android --sdk-version 37.0.0
On first run it’ll start downloading and installing Android SDK, which will take a good while (download took 4 minutes.. install for Android SDK went on for ~70 minutes.. after which i gave gave up.. ).
Run a local server and note the URL, i used http-server
whose default URL is http://127.0.0.1:8080
. Then use ngrok
to serve that over an HTTPS link. (I tried running http-server with SSL but got a Error: self signed certificate
in the end)
1# run http-server
2npx http-server
3
4# run ngrok over http-server to get an HTTPS secure URL
5ngrok http 127.0.0.1:8080 -host-header="127.0.0.1:8080"
Copy the https
forwarding URL ngrok
gives you. For example: https://XXXXXXXXXXXX.ngrok.io
1#expo export --dev --public-url http://127.0.0.1:8080
2expo export --public-url https://XXXXXXXXXXXX.ngrok.io
Exporting takes less than a minute..
(the --dev
is supposed to get rid of --public-url must be a valid HTTPS URL.
error, which it doesn’t..)
dist
├── android-index.json
├── assets
│ ├── 02bc1fa7c0313217bde2d65ccbff40c9
│ ├── 0886a6b127c6057cee83f9c65c7ffd62
│ ├── 09dd345dbd4ec5a0874841d5749ac153
│ ├── fdc01171a7a7ea76b187afcd162dee7d
│ └── ff31215218cf59699e34b7db3a479e6c
├── bundles
│ ├── android-28379830c4e0f74b22adc7bd243f273d.js
│ └── ios-802a95f67ffeeffac160346ff41e54a1.js
└── ios-index.json
Run the exported app dist/
on local server and confirm it’s running ..
1cd dist/
2npx http-server
3curl https://XXXXXXXXXXXX.ngrok.io/android-index.json
1#cd dist/
2
3# create a key and run http-server with SSL
4#openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
5#npx http-server -S -C cert.pem
NOTE: I went with publishing the app using a Netlify URL. And the site gets automatically published when i push code to the repo.. No fussing with ngrok
and http-server
(which are both local). This URL is called by the app, so it needs to be publicly available over the internet.. Something like http://build.myapp.com
is awesome
If you have previously published an Android app with Expo, get the keystore
1expo fetch:android:keystore
Keystore credentials
Keystore password: xxxxxxxxxxxxxx98a9a42e1cxxxxxxxx
Key alias: xxxxxxxxxxxxxxxxxxxxxnBwcmVhY3Ruxxxxxxxx
Key password: xxxxxxxxxxxxxxxxxxxxxx9bcxxxxxxx
Path to Keystore: /media/aamnah/Files/Sites/fppreactnative/fppreactnative.jks
From the project root, run the following
1EXPO_ANDROID_KEYSTORE_PASSWORD="XXXXXXXX" \
2EXPO_ANDROID_KEY_PASSWORD="XXXXXXXX" \
3turtle build:android \
4 --keystore-path /PATH/TO/YOUR/KEYSTORE/XXXXXXXX.jks \
5 --keystore-alias PUT_KEYSTORE_ALIAS_HERE
6 --public-url https://XXXXXXXXXXXX.ngrok.io/android-index.json
--public-url
here is the secure URL we git with ngrok
which is forwarding to https-server
running inside dist/
.aab
file. To get an APK, pass it as a flag --type apk
Build failed after 10 minutes.. =( Removed ~/.turtle/workingdir
and ran the build again. Build failed again because of node version incompatibility. Upgraded node and ran the build again.. Build failed because of an invalid keystore error.. Fixed that, ran the build again. Success! Took around 5 minutes to give me an app bundle .aab
file. Yesssss!
The build is saved inside a folder called expo-apps
inside the user’s Home
directory (Ubuntu).
You need to install Java 8 SDK as turtle-cli
only works with JDK 8. I had 11.0.7 (openjdk) installed on my Ubuntu machine..
The easy way is to install openjdk
and change your Java version
1sudo apt install -y openjdk-8-jdk-headless openjdk-8-jre
1sudo update-alternatives --config java
The more complicated way is to download it from the Oracle website. See [this gist] for instructions on how to download without having to create and login to an Oracle account. Basically, you go to the downloads page, click the download you want, accept the checkbox for license, and instead of clicking the green download button you copy link location, and then you change the otn
part to otn-pub
and open that link in order to download.. (blekh)
https://download.oracle.com/otn-pub/java/jdk/8u251-b08/3d5a2bb8f8d4428bbe94aed7ec7ae784/jdk-8u251-linux-x64.tar.gz
https://download.oracle.com/otn-pub/java/jdk/8u251-b08/3d5a2bb8f8d4428bbe94aed7ec7ae784/jdk-8u251-windows-x64.exe
ERROR: Failed to build standalone app
err: Error: --public-url is invalid - only HTTPS urls are supported
Using --dev
exports the app but i kept getting error when trying to build standalone app with turtle. Ended up installing http-server
in order to configure SSL.
Jul 1 11:22:10 turtle[424759] ERROR: Failed to build standalone app
err: Error: Couldn't find app.json.
at Object.loadAppJSON (/home/aamnah/.nvm/versions/node/v12.18.0/lib/node_modules/turtle-cli/src/bin/utils/project.ts:14:11)
at /home/aamnah/.nvm/versions/node/v12.18.0/lib/node_modules/turtle-cli/src/bin/utils/builder.ts:77:23
at Command.<anonymous> (/home/aamnah/.nvm/versions/node/v12.18.0/lib/node_modules/turtle-cli/src/bin/index.ts:23:12)
platform: "android"
Turtle only works with app.json
and not app.config.js
or app.config.ts
. Changed back to app.json
and it worked.