fastlane-community / fastlane-plugin-ionic

Integrate your Ionic build into your Fastlane setup
MIT License
87 stars 46 forks source link

How to use capacitor instead of cordova #63

Closed Frotty closed 4 years ago

Frotty commented 4 years ago

Hi,

we migrated our app from cordova to capacitor, but this plugin still runs cordova. Is there any way to run the capacitor build command instead?

janpio commented 4 years ago

No, you would have to fork this plugin and edit its code to use Capacitor commands. The CLI of Capacitor is totally different, so this might a bit of work.

mrogunlana commented 2 years ago

Chiming in on this: Since Appflow drastically increased their monthly subscription rate from $120/mo to over $400/mo for their basic plan (re: https://ionic.io/pricing), it seems like a no brainer for app developers with new apps to go with a more cost effient approach to deploying their apps (re: https://www.reddit.com/r/ionic/comments/qh605c/alternatives_to_appflow/). I'm a fan of the fastlane plugin route, but can't use this plugin since it only works with cordova which is fastly becoming obsolete for new apps (re: https://ionic.io/resources/articles/capacitor-vs-cordova-modern-hybrid-app-development).

Since @janpio claims it would be a "bit of work" to fork this library to make it suitable for capacitor, I'm willing to lend a development hand to do so. But, I wonder, has anyone else forked this library to retrofit it for capacitor yet? If not, who would be willing to work with me to convert this project to support capacitor and what effort would be required to do so? Would the author of this library be willing to work with me to update it? I have a app project that calls for an alternative CI solution and I don't want to start from scratch so I'd be willing to do the work, does anyone else feel the same way?

janpio commented 2 years ago

I was the original author, and I am not using Ionic, Cordova or Capacitor any more which is why I donated the plugin to this org, which is loosely connected to fastlane itself. I think @joshdholtz could publish updates if they are ready and considered stable.

mrogunlana commented 2 years ago

@janpio it's been a few days; I think it may be safe to say that @joshdholtz won't have any time in the near future (e.g. in the next week or two) to bother with this. Any chance that you can give me a rough outline of what should be done to make this plugin compatible with Capacitor?

I'm gearing up hardware wise to start development on it and it would be nice to have a quick bullet point list of items to do before I fork this repo.

janpio commented 2 years ago

Sorry, I honestly can not say more than this: Fork the repo, replace all Cordova logic with the Capacitor logic, make it work, done.

mrogunlana commented 2 years ago

Lol, got it. Thank you.

riderx commented 2 years ago

@mrogunlana just in case if you need a solution for live update who was in Appflow too and is too expensive now, check my project https://capgo.app/ i made it because the price of Appflow was too expensive

mrogunlana commented 2 years ago

thanks @riderx I actually figured out how to deploy directly using fastlane without the use of a plugin. I'm using GitLab CI pipelines to accomplish it like so (for all those who find this thread in the future):

Here's the contents of my .gitlab-ci.yml

image: macos-12-xcode-13 # https://docs.gitlab.com/ee/ci/runners/build_cloud/macos/environment.html

stages:
  - release

internal_track_android:
  when: manual
  tags: [ shared-macos-amd64 ]
  before_script:
    - brew tap AdoptOpenJDK/openjdk
    - brew install --cask adoptopenjdk15

    - export JAVA_HOME=$(/usr/libexec/java_home -v 15);

    - echo $JAVA_HOME;
    - java -version

    - brew install --cask android-commandlinetools

    - sdkmanager --update

    - set +o pipefail

    - yes | sdkmanager --licenses
    - yes | sdkmanager --install "platform-tools"
    - yes | sdkmanager --install "build-tools;30.0.2"
    - yes | sdkmanager --install "platforms;android-30"

    - sdkmanager --list_installed

    - set -o pipefail

    - export ANDROID_HOME=$(brew --prefix)/share/android-commandlinetools
    - export ANDROID_SDK_ROOT=$(brew --prefix)/share/android-commandlinetools

    - export APP_VERSION_CODE=$APP_VERSION_CODE;
    - export APP_VERSION_NUMBER=$APP_VERSION_NUMBER;

    - chmod +x ./android/gradlew;

    - npm install -g @ionic/cli
    - npm install --prefer-offline --no-audit
    - node build.js
    - ionic capacitor sync android
  script:
    - export KEY_STORE=$CI_PROJECT_DIR/fastlane/resources/$KEY_STORE;
    - export KEY_STORE_PASSWORD=$KEY_STORE_PASSWORD;
    - export KEY_ALIAS=$KEY_ALIAS;
    - export KEY_PASSWORD=$KEY_PASSWORD;
    - export PLAY_CREDENTIALS_JSON=$PLAY_CREDENTIALS_JSON;

    - echo $KEY_STORE;

    - fastlane android internal
  artifacts:
      paths:
        - android/app/build/outputs/apk/release/app-release.apk

test_flight_ios:
  when: manual
  tags: [ shared-macos-amd64 ]
  before_script:
    - xcodebuild -sdk -version
    - export APP_VERSION_CODE=$APP_VERSION_CODE;
    - export APP_VERSION_NUMBER=$APP_VERSION_NUMBER;
    - npm install -g @ionic/cli
    - npm install --prefer-offline --no-audit
    - node build.js
    - ionic capacitor sync ios
  script:
    - export APP_STORE_CONNECT_API_KEY_ID=$APP_STORE_CONNECT_API_KEY_ID;
    - export APP_STORE_CONNECT_API_ISSUER_ID=$APP_STORE_CONNECT_API_ISSUER_ID;
    - export APP_STORE_CONNECT_API_KEY_CONTENT=$APP_STORE_CONNECT_API_KEY_CONTENT;
    - export CERTIFICATE_STORE_GITLAB_URL="https://gitlab-ci-token:$CI_JOB_TOKEN@gitlab.com/<user/company>/<certificate_store>.git";
    - export MATCH_PASSWORD="<match_certificate_store_password>";
    - fastlane ios beta
  artifacts:
    paths:
      - App.ipa

Here's the contents of my Fastfile:

# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
#     https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
#     https://docs.fastlane.tools/plugins/available-plugins
#

# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane

default_platform(:ios)

platform :ios do
  desc "Push a new beta build to TestFlight"
  lane :beta do

    api_key = app_store_connect_api_key(
        key_id: ENV['APP_STORE_CONNECT_API_KEY_ID'],
        issuer_id: ENV['APP_STORE_CONNECT_API_ISSUER_ID'],
        key_content: ENV['APP_STORE_CONNECT_API_KEY_CONTENT']
    )

    def ensure_temp_keychain(name)
        delete_keychain(
            name: name
        ) if File.exist? File.expand_path("~/Library/Keychains/#{name}-db")
        create_keychain(
            name: name,
            password: 'temppassword',
            unlock: true,
            timeout: 0
        )
    end

    ensure_temp_keychain 'login.keychain'

    match(
        git_url: ENV['CERTIFICATE_STORE_GITLAB_URL'],
        type: "appstore", 
        app_identifier: "x.y.z", 
        api_key: api_key,
        readonly: true,
        keychain_name: "login.keychain",
        keychain_password: "temppassword"
    )

    update_code_signing_settings(
      use_automatic_signing: false,
      path: "./ios/App/App.xcodeproj",
      code_sign_identity: "iPhone Distribution"
    )

    sync_code_signing(
        readonly: true,
        type: "appstore", 
        git_url: ENV['CERTIFICATE_STORE_GITLAB_URL'],
        app_identifier: "x.y.z", 
        api_key: api_key,
        keychain_name: "login.keychain",
        keychain_password: "temppassword",
        git_full_name: "<user_nam>",
        git_user_email: "<user_email>",
        platform: "ios"
    )

    update_project_provisioning(
        xcodeproj: "./ios/App/App.xcodeproj",
        profile: ENV['sigh_com.iak.msi_appstore_profile-path']
    )

    build_app(
        configuration: "Release",
        output_name: "App.ipa",
        output_directory: ".",
        workspace: "./ios/App/App.xcworkspace",
        scheme: "App"
    ) 

    upload_to_testflight(
        api_key: api_key,
        ipa: "App.ipa",
        skip_waiting_for_build_processing: true
    )

  end
end

platform :android do
  desc "Push a new beta build to the Internal Test Track"
  lane :internal do

    gradle(
        project_dir: "./android",
        gradle_path: "./gradlew",
        build_type: "Release",
        task: "assemble",
        print_command: false,
        properties: {
            "android.injected.signing.store.file" => ENV['KEY_STORE'],
            "android.injected.signing.store.password" => ENV['KEY_STORE_PASSWORD'],
            "android.injected.signing.key.alias" => ENV['KEY_ALIAS'],
            "android.injected.signing.key.password" => ENV['KEY_PASSWORD'],
        }
    ) 

    supply(
        package_name: "x.y.z",
        track: 'internal',
        skip_upload_images: true,
        skip_upload_metadata: true,
        skip_upload_screenshots: true,
        json_key_data: ENV['PLAY_CREDENTIALS_JSON']
    )

  end
end

If anyone needs help implementing this, let me know and I'll help you!

riderx commented 2 years ago

@mrogunlana super cool thanks ! But that still need Apple review when you deploy to production ?

mrogunlana commented 2 years ago

@riderx updated Fastfile here: https://github.com/fastlane-community/fastlane-plugin-ionic/issues/63#issuecomment-1074328057 to fix the keychain prompt to allow access to the private key reported here https://github.com/fastlane/fastlane/issues/10589#

and to answer your question, yes, as of now, the Fastfile above just submits the app to testflight; you can manually move that release to production. I'm in the process of updating my CI script to include the Android deployment and can circle back to add a production step so that it will deploy straight into production (if you need me to).

riderx commented 2 years ago

Ok thanks @mrogunlana, so my solution is still a good option since it skip the review step and send direct to users the updates. I will give a try to your Fastlane config it's still interesting for native plugin updates

mrogunlana commented 2 years ago

updated Fastfile here: https://github.com/fastlane-community/fastlane-plugin-ionic/issues/63#issuecomment-1074328057 to reflect fix code signing issues of apps that have signing automatically selected e.g. in the xcodeproj file; it also fixes potential key chain passphrase issues by recreating the keychain and setting the passphrase. The fastlane ios beta track is verified working in my GitLab continuous deployment pipeline. I'll update this thread again once I'm done with the Android lane.

CC: @riderx

mrogunlana commented 2 years ago

I've updated https://github.com/fastlane-community/fastlane-plugin-ionic/issues/63#issuecomment-1074328057 with the final version of the gitlab-ci.yml and Fastfile necessary to deploy Google Play (android) and Testflight (ios) using ionic capacitor and a macos runner. These steps have been tested in the latest SaaS macos runner in GitLab image: macos-12-xcode-13.

Keep in mind that there are several nuances to deploying ionic capacitor in an automated fashion with continuous integration:

  1. Gradle 7 is not compatible to JDK 16+ (see: https://docs.gradle.org/current/userguide/compatibility.html#android and https://developer.android.com/studio/releases/gradle-plugin#compatibility-7-1-0). This is why I am explicitly installing adoptopenjdk15 to mitigate this via brew install --cask adoptopenjdk15
  2. You must setup a keystore and store it in a location the build process has access to e.g. in the repo or cloud storage in order to properly sign android releases, see: https://www.devopsschool.com/blog/how-to-upload-new-keystore-or-app-signing-key-in-google-play-console-after-lost-or-forget-keystore/ for more information. See the gradle.properties setting in the Fastfile above for context.
  3. You must delete the CI keychain and recreate it with a known password in order to store/retrieve the certificate properly, see https://github.com/fastlane/fastlane/issues/10589 for more details. This is why I'm doing this: ensure_temp_keychain 'login.keychain'

If you copy/paste the above CI configuration and Fastfile as a template, you should be able to get your android/ios capacitor app deployed. It represents over 40 hours of debug, testing, trial/error so hopefully it will help someone get off the ground much quicker.

Notes/sources:

  1. Basic setup of the android fastlane workflow: https://medium.com/nerd-for-tech/ci-cd-for-android-using-github-actions-and-gradle-play-publisher-448bd8e42774
  2. Basic setup of the ios fastlane workflow: https://joshstrange.com/setting-up-fastlane-with-ionic-cordova-apps/
  3. Runner/image configuration of the macos-12-xcode-13 image for all those who use a different cloud CI other than Gitlab: https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/macstadium/orka/-/blob/main/toolchain/monterey.yml

PS: the above scripts could be ported into a v2 ionic plugin that supports capacitor. if someone wants to do the port, I would be more than happy to assist you 🚀

keywords for the search algorithm: ionic capacitor fastlane, deploy ionic capacitor

jbchr commented 2 years ago

@mrogunlana for the 3. nuance you mentioned (creating the temp keychain) you can also use https://docs.fastlane.tools/actions/setup_ci/ (put setup_ci on top of the Fastfile) this will create a temp keychain under the hood, will configures match to run in readonly mode and will also only run if it's exectued in a ci environment. Worked for me like charm in Gitlab.

riderx commented 1 year ago

hey @mrogunlana i try to setup fastlane as well, did you have fastlane folder in the root or in each ios/android folder ?

mrogunlana commented 1 year ago

Hi @riderx I have fastlane in root only

riderx commented 1 year ago

ok thanks ! i'm currently trying to configure it with github actions :)

mrogunlana commented 1 year ago

Ok, me know how it goes

riderx commented 1 year ago

it worked with a mix of your work and other tutorials tomorrow i try for android, i will write a blog article about it, that super important:)

mrogunlana commented 1 year ago

in preparation for ios, make sure you update your fastline to the latest version within the pipeline. you can accomplish this by putting the following in your fastfile:

# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane
update_fastlane

default_platform(:ios)

re: Unable to upload to testflight using Xcode 14 beta

riderx commented 1 year ago

i'm using a premade github action who do it for me i believe, you can see my config here: https://github.com/Cap-go/capgo/blob/main/.github/workflows/build.yml and the build logs here: https://github.com/Cap-go/capgo/actions/runs/3337101755/jobs/5523026733

mrogunlana commented 1 year ago

I see this: https://github.com/Cap-go/capgo/blob/main/.github/workflows/build.yml#L111 which probably translates to macOS 12/xcode 14 as long as when you run upload_to_testflight that it uses altool in the latest version of fastlane instead of the old transporter, you should be good.

riderx commented 1 year ago

Made it work for android too : https://github.com/Cap-go/capgo/blob/d88194543a6a472bd833b686753893b914b4aef9/.github/workflows/build.yml#L69 That was not easy ^^ I go to sleep and tomorrow I write 2 blogs about it.

riderx commented 1 year ago

So here are the blog articles:

riderx commented 1 year ago

Thanks a lot @mrogunlana you gave me the right tips ! I added the link to your message who helped me, in the thanks section of the android one

mrogunlana commented 1 year ago

Thanks @riderx for writing those articles! I see this thread mentioned in the source for the android post, but I don't see it listed for the ios post. Would be nice to credit this thread on both articles. Also, feel free to mention my name and github profile if you'd like for anyone needing help setting this up

riderx commented 1 year ago

Oh, you are right !! I'm sorry, I had only android in head for your help. But you definitely helped for both, added to IOS. I have modified the mention to add your name.

palfaro91 commented 1 year ago

@riderx updated Fastfile here: #63 (comment) to fix the keychain prompt to allow access to the private key reported here fastlane/fastlane#10589

and to answer your question, yes, as of now, the Fastfile above just submits the app to testflight; you can manually move that release to production. I'm in the process of updating my CI script to include the Android deployment and can circle back to add a production step so that it will deploy straight into production (if you need me to).

Hi @mrogunlana do you think you could show me an example of the production step? I was over here thinking that that would only be accomplished manually but it sounds like it could be automated.

mrogunlana commented 1 year ago

good question @palfaro91

Sure thing, I whipped up the example snippet below. In the meantime, check out: https://docs.fastlane.tools/actions/ and specifically the https://docs.fastlane.tools/actions/upload_to_app_store/ action which shows the specific keyword that we need to upload the *.ipa generated from the build_app step in the script above.

The line of code you'll need is:

fastlane deliver --ipa "App.ipa" --submit_for_review instead of the upload_to_testflight step.

The code would then be updated to look like so:

# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
#     https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
#     https://docs.fastlane.tools/plugins/available-plugins
#

# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane

default_platform(:ios)

platform :ios do
  desc "Push a new beta build to TestFlight"
  lane :beta do

    api_key = app_store_connect_api_key(
        key_id: ENV['APP_STORE_CONNECT_API_KEY_ID'],
        issuer_id: ENV['APP_STORE_CONNECT_API_ISSUER_ID'],
        key_content: ENV['APP_STORE_CONNECT_API_KEY_CONTENT']
    )

    def ensure_temp_keychain(name)
        delete_keychain(
            name: name
        ) if File.exist? File.expand_path("~/Library/Keychains/#{name}-db")
        create_keychain(
            name: name,
            password: 'temppassword',
            unlock: true,
            timeout: 0
        )
    end

    ensure_temp_keychain 'login.keychain'

    match(
        git_url: ENV['CERTIFICATE_STORE_GITLAB_URL'],
        type: "appstore", 
        app_identifier: "x.y.z", 
        api_key: api_key,
        readonly: true,
        keychain_name: "login.keychain",
        keychain_password: "temppassword"
    )

    update_code_signing_settings(
      use_automatic_signing: false,
      path: "./ios/App/App.xcodeproj",
      code_sign_identity: "iPhone Distribution"
    )

    sync_code_signing(
        readonly: true,
        type: "appstore", 
        git_url: ENV['CERTIFICATE_STORE_GITLAB_URL'],
        app_identifier: "x.y.z", 
        api_key: api_key,
        keychain_name: "login.keychain",
        keychain_password: "temppassword",
        git_full_name: "<user_nam>",
        git_user_email: "<user_email>",
        platform: "ios"
    )

    update_project_provisioning(
        xcodeproj: "./ios/App/App.xcodeproj",
        profile: ENV['sigh_com.iak.msi_appstore_profile-path']
    )

    build_app(
        configuration: "Release",
        output_name: "App.ipa",
        output_directory: ".",
        workspace: "./ios/App/App.xcworkspace",
        scheme: "App"
    ) 

        deliver(
           # build_number: '830',
               ipa: "App.ipa",
           submit_for_review: true,
           automatic_release: true,
           force: true, # Skip HTML report verification
           skip_metadata: true,
           skip_screenshots: true
        )

  end
end

...

Hope this helps! Let me know if you need any more guidance.

palfaro91 commented 1 year ago

@mrogunlana Thank you so much! Let me check out your example and the links you sent and I will get back to you. Truly appreciate the guidance!🥇