Search code examples
iosxcodereact-nativefastlane

React Native and iOS Native Builds with Fastlane, profile-related issues


I have a React Native app that I am pairing with Fastlane to build Android AABs and whatever the iOS equivalent is (IPAs?). I have already got the Android side of the build, codesigning and publishing to the Google Play Console working, and have gone through the whole process of setting up a Development Account with Google, submitting the AAB release to them, having them approve it, and getting my beta testers "Early Access" to the app from a closed track on Google Play.

My Fastfile for this project looks like this:

default_platform(:ios)

platform :ios do
  desc "iOS Build"
  lane :staging do
    puts "iOS staging build"
    gym(
      scheme: "StagingScheme",
      project: "./ios/myapp.xcodeproj"
    )
  end
end

platform :android do
  desc "Android build"
  lane :staging do
    puts "Android staging build"
    gradle(task: 'clean', project_dir: './android/')
    gradle(
      task: 'bundle',
      build_type: 'Release',
      project_dir: './android/'
    )
  end
end

As you can see, in the Android platform/lane, I use Gradle to clean the project and then bundle the release, which is what produces the codesigned AAB. I then log in to Google Play Console, create a new release under my closed track, manually upload the AAB, and submit the changes for Google to review. It is a process that is at least working!

Now I need to do the same exact thing inside the iOS platform/lane up above. It sounds like gym is a Fastlane command that does this for me: I'm happy to use it if its easy to actually use, but I am not married to it.

All I'm looking to do when I run fastlane ios staging is:

  1. Clean the project from any previous builds
  2. Build the deliverable artifact (again I assume this is an IPA, but please keep me honest!)
  3. Codesign the artifact
  4. I will then manually upload the codesigned artifact to whatever is the iOS/Apple equivalent of a "closed track" (Test Flight perhaps?)

With the current configuration, when I run fastlane ios staging I get the following error:

/Users/myuser/myapp/ios/myapp.xcodeproj: error: No profiles for 'com.memyself.ios' were found: Xcode couldn't find any iOS App Development provisioning profiles matching 'com.memyself.ios'. Automatic signing is disabled and unable to generate a profile. To enable automatic signing, pass -allowProvisioningUpdates to xcodebuild. (in target 'myapp' from project 'myapp')

It may be important to note that the StagingScheme value is just something I put in the Fastfile, I didn't actually go into XCode or its CLI tools and create a scheme called StagingScheme, so that may be an upstream omission on my part that is causing things to fail downstream. My understanding was that the scheme would be created for me if it didn't already exist, but if that's not the case, please just explain to me what I need to do to create it!

Having said that, it sounds like I need to add a profile somewhere? Can anyone explain to me what I would need to do here and what these profiles would look like? And if they have anything to do with codesigning or autosigning, please explain to me what autosigning is and how it compares to other codesigning options.

Again, at the end of the day I just need to clean the project, build an IPA and codesign it. Any way of getting to that state with Fastlane is a feasible solution, at least at this time! Thanks in advance!


Solution

  • First of all, yes, when we compile an iOS app the output is an IPA file.

    About tracks

    Apple "tracks" work differently. Every you upload a new build, you can add it to either:

    • Internal testing: up to 100 members registered to your AppStore Connect, no app review required;
    • External testing: up to 10.000 members, invited via email or by clicking a link. Requires the build to go through Apple's review process (although it's usually a faster review than the one required to publish to the store.

    There is no way of separating Production and Staging builds on the AppStore Connect or on TestFlight.

    If you really need that separation, maybe you could use version or build numbers to differ one from the other, and create an internal pattern for your project, so you know which one is which.

    Another [and, in my opinion, better] option would be to use different Bundle Identifiers for production and staging environments (which is the approach I use), but this requires having different apps registered to the AppStore Connect. Their "lanes" will not be integrated. You could, potentially, upload a build to the Staging app and to the Production app at the same time, with the same version and build number on each, so you can more easily manually track which version on the Staging app is equivalent to which version on the Production app.

    If you want to follow the second approach, lets first duplicate your main Target on Xcode to create a Staging target:

    1. On Xcode, press CMD+1 (if not on this tab already)
    2. tap on your project name
    3. select your main(and only) target from the Targets list
    4. press CMD+D and rename the copy. You can call it MyApp Staging
    5. Tap on the new target and edit the bundle identifier to the staging identifier you want to use.

    Then duplicate your Scheme, to work with the new target:

    1. Tap on your default scheme (right on the left side of where you pick the device/simulator
    2. Tap on New scheme
    3. Select your newly created target
    4. Rename the new scheme as you need
    5. Click ok.

    About FastLane

    For cleaning your build before generating a new one, you can add clean_build_artifacts right in the beginning of the lane and clean: true as a parameter to gym, so adapting your own lane code it would be:

    platform :ios do
      desc "iOS Build"
      lane :staging do
        puts "iOS staging build"
    
        clean_build_artifacts
    
        gym(
          scheme: "StagingScheme",
          project: "./ios/myapp.xcodeproj",
          clean: true
        )
      end
    end
    

    (this is based on the lane code you provided, I haven't tested it)

    About the error

    The error you're getting is because you probably didn't install the Provisioning Profiles. Make sure you have Automatically manage signing checked on the Signing and Capabilities tab of your project on Xcode.

    Also, check out the "Cert and Sigh" section of this document to understand how to handle and provisioning profiles through FastLane. If you want to take a step further, check out match.

    Uploading to TestFlight

    Last but not least, check out upload_to_testflight method. If you want to upload your IPAs manually through the Transporter app, you can, but there's really no benefit in doing so, so this upload_to_testflight method will save you some time.

    About Provisioning Profiles and Signing

    Provisioning profiles basically determines who (which devices) can install an app, and which "capabilities" the app is allowed to use (like Push Notifications, SignIn with Apple, In-app purchase, background modes, bluetooth and so on). (More details about profiles here) (More details about capabilities here)

    Back in the day, this used to be a bureaucratic process. You'd have to open Apple developer website, create a profile, select the options you needed, download it, install it and they would expire from time to time.

    A few years ago, apple implemented the option to enable capabilities from Xcode, so you wouldn't have to worry about that yourself, but since you want to handle that from inside Github Actions, you can use Fastlane's Sigh

    About not using Xcode directly, keep in mind that these settings (automatically signing and enabling capabilities) only have to be set once for each Target of your app, and not with every build.

    If you still need to update it from time to time (in case you are always, automatically, creating new Targets from scripts, like I am, you have a few options:

    For enabling capabilities

    There's a file in your project called YOUR_PROJECT.entitlements. It's an XML that holds information on the capabilities that are enabled, and you could easily edit this file using python or ruby before building the app, but to be honest, I'm not sure editing it without opening the project from Xcode afterwards will work (It'd be easy to test it, but this is the kind of setting you'll only change once in a while (usually if you add new features to your app), even if you're constantly adding new targets to your app. (More information on entitlements here)

    For enabling automatic signing

    The the easiest one is to use FastLane's enable_automatic_code_signing option.

    Also, there's the wrong way: Xcode has a proprietary file format (.pbxproj), which is not always easy to manipulate, but some fields are very straightforward. Theoretically you could run a script that finds the CODE_SIGN_STYLE key inside the file and changes its value to Automatic, and changes DEVELOPMENT_TEAM key to your Development Team's ID (you can find it on the account section of the Apple Developer website) I do not recommend this because it's very easy to break such file.*

    Hope this helps!