expo / turtle

Standalone app builder service
MIT License
384 stars 29 forks source link

IPA build is not working #282

Open tobiasbenkner opened 3 years ago

tobiasbenkner commented 3 years ago

Hi,

I followed this guide https://www.robincussol.com/build-standalone-expo-apk-ipa-with-turtle-cli/ to build the ipa file. The build was successful. Then I uploaded the ipa file to the App Store. Installed TestFlight to install the App on my IPhone. When I open the App following error occur.

Error

Could not connect to development server
...
URL: http://127.0.0.1:8000/bundles/ios-8beb0c...9b.js

Build Environment

build-ios.sh

#!/bin/bash
[ -z "${EXPO_IOS_DIST_P12_PASSWORD}" ] && echo "EXPO_IOS_DIST_P12_PASSWORD is unset" && exit 1;
[ -z "${APPLE_TEAM_ID}" ] && echo "APPLE_TEAM_ID is unset" && exit 1;
[ -z "${BUILD_NUMBER}" ] && echo "BUILD_NUMBER is unset" && exit 1;

printf "\n\nInstall imagemagick\n"
brew install imagemagick

printf "\n\nInstall Expo\n"
npm install -g expo-cli || exit 1;

printf "\n\nInstall turtle-cli\n"
npm install -g turtle-cli || exit 1;

printf "\n\nInstall yarn install\n"
yarn install

printf "\n\nSetup SDK\n"
turtle setup:ios --sdk-version 39.0.3

printf "\n\nRemove Alpha Channel and replace transparency with white\n"
find assets -name "*.png" -exec convert "{}" -background white -alpha remove -alpha off "{}" \;

printf "\n\nUpdate buildNumber\n"
jq ".expo.ios.buildNumber = \"$BUILD_NUMBER\"" app.json > app.new.json && \
  mv app.new.json app.json

printf "\n\nBuild Expo\n"
rm -rf dist
expo export --dev --public-url http://127.0.0.1:8000

printf "\n\nStart Webserver for dist\n"
cd dist || exit 1;
python3 -m http.server &
cd ..

printf "\n\nBuild iOS\n"
turtle build:ios \
  --team-id "${APPLE_TEAM_ID}" \
  --dist-p12-path ios_distribution.p12 \
  --provisioning-profile-path example_Test.mobileprovision \
  --allow-non-https-public-url \
  --public-url http://127.0.0.1:8000/ios-index.json \
  -o app.ipa

Build-Log

What should I do?

Is this behavior normal? Should I provide every build version on a public server? It feels wrong to keep all versions public. On the Android build I don't need to do it.

Thank you for your help!!

Greets, Tobias

jpcodr commented 3 years ago

Hello @tobiasbenkner i have the same issue. Actually, i wrote on the expo forums (Standalone iOS app builded with turtle-cli fails)

Did you found any solution?

tobiasbenkner commented 3 years ago

¡Hola! @jpcodr

I could not find a solution that works for IOS on the local computer for testing purpose.

For the production I would definitely choose a server that provides the sources publicly. Just for the reason of the updates. They will come over the air instead of the App store or Play store. Your updates will be available directly and you don't have to wait for a review from apple or google.

Free solution for https public You can use Github or Gitlab Pages for Expo bundles.

Artifactory You can host e.g. Artifactory and get ssl certificates with Let's Encrypt. Inside of Artifactory you can create a public repository where you store your Expo Bundles. The benifit is that you can just upload, download and deletes files via a web ui.

version: '3'

volumes:
  artifactory_home:
  artifactory_db:

services:

  artifactory:
    image: docker.bintray.io/jfrog/artifactory-oss:7.4.3
    restart: always
    volumes:
      - artifactory_home:/var/opt/jfrog/artifactory
      - /etc/localtime:/etc/localtime:ro
      - /backup:/backup:ro
    ulimits:
      nproc: 65535
      nofile:
        soft: 32000
        hard: 40000
    logging:
      driver: json-file
      options:
        max-size: "50m"
        max-file: "10"
    environment:
      - JF_SHARED_DATABASE_TYPE=postgresql
      - JF_SHARED_DATABASE_USERNAME=user
      - JF_SHARED_DATABASE_PASSWORD=secret
      - JF_SHARED_DATABASE_URL=jdbc:postgresql://artifactory_postgres:5432/artifactory
      - JF_SHARED_DATABASE_DRIVER=org.postgresql.Driver
    depends_on:
      - artifactory_postgres

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.artifactory.rule=Host(`artifactory.domain.tld`) && PathPrefix(`/`)"
      - "traefik.http.routers.artifactory.tls=true"
      - "traefik.http.routers.artifactory.tls.certresolver=le"
      - "traefik.http.services.artifactory.loadbalancer.server.port=8082"

  artifactory_postgres:
    image: postgres:9.6.11
    environment:
      - POSTGRES_DB=artifactory
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=secret
    volumes:
      - artifactory_db:/var/lib/postgresql/data
      - /etc/localtime:/etc/localtime:ro
    restart: always
    logging:
      driver: json-file
      options:
        max-size: "50m"
        max-file: "10"
    ulimits:
      nproc: 65535
      nofile:
        soft: 32000
        hard: 40000

NGINX You can also start a Nginx Server and host your bundles there. it's light weighted but no gui. For the certificates I would also use Let's encrypt.

local https server this solution can also work locally but I didn't tried it out. https://www.npmjs.com/package/https-localhost maybe this can work out for locally testing and debugging.

Solution For production I would use Gitlab or Github Pages. There are to 99,9% available and free. You don't need to take care of updates, security issues, and so on.

For local debugging I would try the local https server. Maybe it works out of the box. In my point of view it's very complicated in the beginning to understand the certificates workflow. You need to generate your own generated self signed certificates and you need trust them that you will get a valid connection to your https server.

I hope I could help!

¡Saludos!

jpcodr commented 3 years ago

Thanks for your suggestions @tobiasbenkner.

We have an nginx server running, so we can use that to serve the files. However, I think this is a bug that should be fixed.

Thanks again.

Robotex commented 3 years ago

I encountered the same issue while trying to make a build for internal testing, running a local https server didn't help because turtle-cli doesn't accept the self signed certificate so I ended up setting up a ngrok tunnel and removing the --dev flag from export command. I agree that this bug should be fixed.

jnoyola commented 3 years ago

I opened a very similar issue linked above before finding this one. Could we get some traction on this? It seems like a pretty major bug in a pretty major feature.

charles-m-knox commented 3 years ago

For what it's worth, I was able to find a solution to this problem using Let's Encrypt with a subdomain you can control, without having to upload any of your files anywhere.

Context: https://github.com/expo/turtle/issues/302#issuecomment-809848518

Guide: https://github.com/charles-m-knox/space-codes#building-locally

susonthapa commented 2 years ago

@charles-m-knox , can you please fix the link. It's dead.

charles-m-knox commented 2 years ago

@susonthapa I took it down, sorry about that! I think I have a copy of the original article somewhere, I'll try and post it here in a moment.

susonthapa commented 2 years ago

Thank you @charles-m-knox for the quick reply. I was kinda stuck here. Did you manage to get the ios app working completely offline?

charles-m-knox commented 2 years ago

@susonthapa Yep I did!

susonthapa commented 2 years ago

Great! Looking forward to your solution.

charles-m-knox commented 2 years ago

@susonthapa Here you go, best of luck! P.S. I don't own a Mac or do Expo app development any more, so I probably can't help if issues arise : (

Building locally

Building locally is required because the mp3 files in the assets/audio directory are 60mb each on average, and Expo's build servers will reject them because they're too big (Cloudfront rejects them as well).

First, install Turtle:

npm install -g turtle-cli
# if the above fails on Mac M1 due to vips, install vips via brew:
brew install vips # this will install a LOT of stuff
# retry installing turtle-cli

Since we are building locally, we have to create a TLS-enabled (and trusted) file server, which will host the dist files from Expo, including the build manifests.

export BUILD_DOMAIN=turtlebuilder.site.com

Install certbot so we can acquire a TLS certificate:

brew install certbot

Acquire a TLS certificate for your domain using a DNS acme challenge - you have to run as sudo because certbot requires access to /etc/letsencrypt as well as /var/log/letsencrypt:

sudo certbot certonly --manual \
    -d "${BUILD_DOMAIN}" \
    --preferred-challenges dns-01 \
    --server https://acme-v02.api.letsencrypt.org/directory

# you will be prompted for DNS verification, don't press anything and continue reading.

This will require you to go to your DNS portal (such as Cloudflare) and create a TXT record under _acme-challenge.turtlebuilder.site.com with the value it specifies.

In a new terminal window, check the DNS record:

# verify that the record shows up in DNS before proceeding
dig TXT _acme-challenge.${BUILD_DOMAIN}

Back in your certbot terminal window, hit enter, and it should succeed.

Next, you have to update your local DNS. Your computer must believe that your local system's IP address is actually ${BUILD_DOMAIN}. There are many ways to do this; the best options are:

Now that you have a valid certificate for your domain and your device(s) are setup to work with your custom DNS settings, you can export your assets/bundles/manifests with Expo to the local dist directory - by specifying --public-url, we will be telling Turtle that everything is accessible via that URL when it tries to download all the assets for building:

expo export --public-url https://${BUILD_DOMAIN} --force

Finally, run Caddy - the ./caddy/Caddyfile will mount ./dist and it will be directly accessible via https://${BUILD_DOMAIN} after starting:

brew install caddy # if not installed
cd caddy
BUILD_DOMAIN=${BUILD_DOMAIN} sudo -E caddy run

Building a simulator app

Luckily, this step is much easier than the official IPA build, since you don't have to sign the package:

turtle build:ios \
    --public-url https://${BUILD_DOMAIN}/ios-index.json \
    -t simulator

Building the official IPA file

Finally, get ready to run the final build step. A few things to note about this:

#!/bin/zsh -e
echo -n "iOS p12 certificate password: "
read -s DIST_P12_PASSWORD
echo ""
echo "starting..."
EXPO_IOS_DIST_P12_PASSWORD=${DIST_P12_PASSWORD} \
    turtle build:ios \
    --public-url https://${BUILD_DOMAIN}/ios-index.json \
    --team-id 01ABC234DE \
    --dist-p12-path ../certificates/apple-distribution-xcode-wildcard.p12 \
    --provisioning-profile-path ../certificates/Space_Codes_Xcode.mobileprovision \
    -t archive

In my experience, during every IPA build, I get prompted for my Mac local user account password ~4 times or so, maybe more.

Managing your distribution certificates

https://www.robincussol.com/build-standalone-expo-apk-ipa-with-turtle-cli/#53-build-ipa https://support.magplus.com/hc/en-us/articles/203808748-iOS-Creating-a-Distribution-Certificate-and-p12-File

You have to export and use your Xcode wildcard p12 certificate. Other certificates don't seem to work, despite my best efforts.