diff --git a/.github/actions/install-and-build-sdk/action.yml b/.github/actions/install-and-build-sdk/action.yml index 5ba82e4bc2..f79f913aa5 100644 --- a/.github/actions/install-and-build-sdk/action.yml +++ b/.github/actions/install-and-build-sdk/action.yml @@ -16,11 +16,6 @@ runs: cd package/native-package/ yarn shell: bash - - name: Install & Build the Expo Package - run: | - cd package/expo-package/ - yarn - shell: bash - name: Install & Build the Sample App working-directory: examples/SampleApp run: yarn diff --git a/.github/workflows/sample-distribution.yml b/.github/workflows/sample-distribution.yml index 981c8bb2c6..410292fdbd 100644 --- a/.github/workflows/sample-distribution.yml +++ b/.github/workflows/sample-distribution.yml @@ -17,7 +17,7 @@ jobs: runs-on: [macos-15] strategy: matrix: - node-version: [ 24.x ] + node-version: [24.x] steps: - name: Connect Bot uses: webfactory/ssh-agent@v0.7.0 @@ -51,18 +51,18 @@ jobs: bundle exec pod install - name: Build and release Testflight QA working-directory: examples/SampleApp - run: bundle exec fastlane deploy_to_testflight_qa deploy:${{ github.ref == 'refs/heads/develop' }}; + run: bundle exec fastlane ios deploy_to_testflight_qa deploy:${{ github.ref == 'refs/heads/develop' }}; env: MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }} MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }} APPSTORE_API_KEY: ${{ secrets.APPSTORE_API_KEY }} - build_and_deploy_android_s3: + build_and_deploy_android_firebase: name: Build SampleApp Android and Deploy-${{ github.ref == 'refs/heads/develop' }} runs-on: ubuntu-latest strategy: matrix: - node-version: [ 24.x ] + node-version: [24.x] steps: - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 @@ -74,26 +74,12 @@ jobs: distribution: 'zulu' java-version: '17' check-latest: true + - uses: ./.github/actions/ruby-cache - name: Install && Build - SDK and Sample App uses: ./.github/actions/install-and-build-sdk - - name: Build + - name: Build and deploy Android Firebase working-directory: examples/SampleApp - run: | - mkdir android/app/src/main/assets - mkdir tmp - yarn react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest tmp - cd android - rm -rf $HOME/.gradle/caches/ && ./gradlew assembleRelease - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1 - if: ${{ github.ref == 'refs/heads/develop' }} - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: us-east-1 - - name: Upload APK - if: ${{ github.ref == 'refs/heads/develop' }} - # https://getstream.io/downloads/rn-sample-app.apk - run: | - cp examples/SampleApp/android/app/build/outputs/apk/release/app-release.apk rn-sample-app.apk - aws s3 cp rn-sample-app.apk s3://${{ secrets.AWS_S3_BUCKET }} --sse AES256 + run: bundle exec fastlane android firebase_build_and_upload deploy:${{ github.ref == 'refs/heads/develop' }}; + env: + ANDROID_FIREBASE_APP_ID: ${{ secrets.ANDROID_FIREBASE_APP_ID }} + FIREBASE_CREDENTIALS_JSON: ${{ secrets.FIREBASE_CREDENTIALS_JSON }} diff --git a/examples/SampleApp/.gitignore b/examples/SampleApp/.gitignore index 1f3e68a22e..7388cefebf 100644 --- a/examples/SampleApp/.gitignore +++ b/examples/SampleApp/.gitignore @@ -73,3 +73,7 @@ yarn-error.log !.yarn/releases !.yarn/sdks !.yarn/versions + +# Credentials +credentials/ +app-build/ diff --git a/examples/SampleApp/android/app/build.gradle b/examples/SampleApp/android/app/build.gradle index e1c59595a5..39b1680d7a 100644 --- a/examples/SampleApp/android/app/build.gradle +++ b/examples/SampleApp/android/app/build.gradle @@ -79,15 +79,15 @@ android { buildToolsVersion rootProject.ext.buildToolsVersion compileSdk rootProject.ext.compileSdkVersion - namespace "com.sampleapp" + namespace "io.getstream.reactnative.sampleapp" defaultConfig { - applicationId "com.sampleapp" + applicationId "io.getstream.reactnative.sampleapp" minSdkVersion rootProject.ext.minSdkVersion multiDexEnabled true targetSdkVersion rootProject.ext.targetSdkVersion vectorDrawables.useSupportLibrary = true - versionCode 22 + versionCode 1 versionName "0.0.22" } diff --git a/examples/SampleApp/android/app/google-services.json b/examples/SampleApp/android/app/google-services.json index 1d5c701c81..ec09246afb 100644 --- a/examples/SampleApp/android/app/google-services.json +++ b/examples/SampleApp/android/app/google-services.json @@ -62,7 +62,7 @@ "client_info": { "mobilesdk_app_id": "1:674907137625:android:5effa1cd0fef9003d7f348", "android_client_info": { - "package_name": "com.sampleapp" + "package_name": "io.getstream.reactnative.sampleapp" } }, "oauth_client": [ @@ -98,7 +98,7 @@ "client_info": { "mobilesdk_app_id": "1:674907137625:android:07c76802bbfd5654d7f348", "android_client_info": { - "package_name": "com.sampleapp.rnpushtest" + "package_name": "io.getstream.reactnative.sampleapp.rnpushtest" } }, "oauth_client": [ diff --git a/examples/SampleApp/android/app/src/androidTest/java/com/sampleapp/DetoxTest.java b/examples/SampleApp/android/app/src/androidTest/java/com/sampleapp/DetoxTest.java index df226139a6..9557ec76a9 100644 --- a/examples/SampleApp/android/app/src/androidTest/java/com/sampleapp/DetoxTest.java +++ b/examples/SampleApp/android/app/src/androidTest/java/com/sampleapp/DetoxTest.java @@ -1,4 +1,4 @@ -package com.sampleapp; +package io.getstream.reactnative.sampleapp; import com.wix.detox.Detox; import com.wix.detox.config.DetoxConfig; @@ -24,7 +24,7 @@ public void runDetoxTests() { DetoxConfig detoxConfig = new DetoxConfig(); detoxConfig.idlePolicyConfig.masterTimeoutSec = 90; detoxConfig.idlePolicyConfig.idleResourceTimeoutSec = 60; - detoxConfig.rnContextLoadTimeoutSec = (com.sampleapp.BuildConfig.DEBUG ? 180 : 60); + detoxConfig.rnContextLoadTimeoutSec = (io.getstream.reactnative.sampleapp.BuildConfig.DEBUG ? 180 : 60); Detox.runTests(mActivityRule, detoxConfig); } diff --git a/examples/SampleApp/android/app/src/main/java/com/sampleapp/MainActivity.kt b/examples/SampleApp/android/app/src/main/java/com/sampleapp/MainActivity.kt index f3ca98b78b..e1de600051 100644 --- a/examples/SampleApp/android/app/src/main/java/com/sampleapp/MainActivity.kt +++ b/examples/SampleApp/android/app/src/main/java/com/sampleapp/MainActivity.kt @@ -1,4 +1,4 @@ -package com.sampleapp +package io.getstream.reactnative.sampleapp import com.facebook.react.ReactActivity import com.facebook.react.ReactActivityDelegate diff --git a/examples/SampleApp/android/app/src/main/java/com/sampleapp/MainApplication.kt b/examples/SampleApp/android/app/src/main/java/com/sampleapp/MainApplication.kt index 69b92b8443..84c3f9a65e 100644 --- a/examples/SampleApp/android/app/src/main/java/com/sampleapp/MainApplication.kt +++ b/examples/SampleApp/android/app/src/main/java/com/sampleapp/MainApplication.kt @@ -1,4 +1,4 @@ -package com.sampleapp +package io.getstream.reactnative.sampleapp import android.app.Application import com.facebook.react.PackageList diff --git a/examples/SampleApp/fastlane/Fastfile b/examples/SampleApp/fastlane/Fastfile index bf10e28713..321188bab7 100644 --- a/examples/SampleApp/fastlane/Fastfile +++ b/examples/SampleApp/fastlane/Fastfile @@ -1,13 +1,23 @@ -default_platform(:ios) skip_docs +# Common Configuration github_repo = ENV['GITHUB_REPOSITORY'] || 'GetStream/stream-chat-react-native' -bundle_id = 'io.getstream.reactnative.SampleApp' -xcode_project = 'ios/SampleApp.xcodeproj' -xcode_workspace = 'ios/SampleApp.xcworkspace' root_path = File.absolute_path('../../../') sdk_size_ext = 'KB' @force_check = false +build_output_directory = "./app-build" + +# iOS Platform Configuration +bundle_id = 'io.getstream.reactnative.SampleApp' +xcode_project = 'ios/SampleApp.xcodeproj' +xcode_workspace = 'ios/SampleApp.xcworkspace' +output_ipa_name = "reactnativesampleapp.ipa" + +# Android Platform Configuration +package_name = 'io.getstream.reactnative.sampleapp' +output_apk_name = "reactnativesampleapp.apk" +apk_path = "#{build_output_directory}/#{output_apk_name}" + before_all do if is_ci @@ -20,82 +30,121 @@ end ###### iOS lanes ###### ####################### -lane :deploy_to_testflight_qa do |options| - match_me - - settings_to_override = { - BUNDLE_IDENTIFIER: bundle_id, - PROVISIONING_PROFILE_SPECIFIER: "match AppStore #{bundle_id}" - } - - increment_version_number( - version_number: load_json(json_path: './package.json')['version'], - xcodeproj: xcode_project - ) - - current_build_number = app_store_build_number( - api_key: appstore_api_key, - live: false, - app_identifier: bundle_id +platform :ios do + lane :deploy_to_testflight_qa do |options| + match_me + + deploy = options.fetch(:deploy, false) + + UI.message("Deploying to Testflight: #{deploy}") + + settings_to_override = { + BUNDLE_IDENTIFIER: bundle_id, + PROVISIONING_PROFILE_SPECIFIER: "match AppStore #{bundle_id}" + } + + gym( + workspace: xcode_workspace, + scheme: 'SampleApp', + export_method: 'app-store', + export_options: './fastlane/testflight_gym_export_options.plist', + silent: true, + clean: true, + xcargs: settings_to_override, + include_symbols: true, + output_directory: build_output_directory ) - increment_build_number( - build_number: current_build_number + 1, - xcodeproj: xcode_project - ) + if deploy + increment_version_number( + version_number: load_json(json_path: './package.json')['version'], + xcodeproj: xcode_project + ) - gym( - workspace: xcode_workspace, - scheme: 'SampleApp', - export_method: 'app-store', - export_options: './fastlane/testflight_gym_export_options.plist', - silent: true, - clean: true, - xcargs: settings_to_override, - include_symbols: true, - output_directory: './dist' - ) + current_build_number = app_store_build_number( + api_key: appstore_api_key, + live: false, + app_identifier: bundle_id + ) + + increment_build_number( + build_number: current_build_number + 1, + xcodeproj: xcode_project + ) - if options[:deploy] - begin upload_to_testflight( groups: ['Testers'], changelog: 'Lots of amazing new features to test out!', - reject_build_waiting_for_review: false + reject_build_waiting_for_review: false, + ipa: "#{build_output_directory}/#{output_ipa_name}" ) - rescue StandardError => e - if e.message.include?('Another build is in review') - UI.important('Another build is already in beta review. Skipping beta review submission') - else - UI.user_error!(e) - end + else + UI.message("Skipping Testflight upload! (deploy: #{deploy})") end end -end -private_lane :appstore_api_key do - @appstore_api_key ||= app_store_connect_api_key( - key_id: 'MT3PRT8TB7', - issuer_id: '69a6de96-0738-47e3-e053-5b8c7c11a4d1', - key_content: ENV.fetch('APPSTORE_API_KEY', nil), - in_house: false - ) -end - -desc "If `readonly: true` (by default), installs all Certs and Profiles necessary for development and ad-hoc.\nIf `readonly: false`, recreates all Profiles necessary for development and ad-hoc, updates them locally and remotely." -lane :match_me do |options| - custom_match( - api_key: appstore_api_key, - app_identifier: [bundle_id], - readonly: options[:readonly], - register_device: options[:register_device] - ) + private_lane :appstore_api_key do + @appstore_api_key ||= app_store_connect_api_key( + key_id: 'MT3PRT8TB7', + issuer_id: '69a6de96-0738-47e3-e053-5b8c7c11a4d1', + key_content: ENV.fetch('APPSTORE_API_KEY', nil), + in_house: false + ) + end + + desc "If `readonly: true` (by default), installs all Certs and Profiles necessary for development and ad-hoc.\nIf `readonly: false`, recreates all Profiles necessary for development and ad-hoc, updates them locally and remotely." + lane :match_me do |options| + custom_match( + api_key: appstore_api_key, + app_identifier: [bundle_id], + readonly: options[:readonly], + register_device: options[:register_device] + ) + end end ########################### ###### Android lanes ###### ########################### +platform :android do + lane :firebase_build_and_upload do |options| + deploy = options.fetch(:deploy, false) + + UI.message("Deploying to Firebase: #{deploy}") + + # Clean + gradle( + task: "clean", + project_dir: "./android" + ) + + # Build the AAB + gradle( + task: "assemble", + build_type: "Release", + project_dir: "./android" + ) + + Dir.chdir('..') do + sh("mkdir -p #{build_output_directory} && mv -f #{lane_context[SharedValues::GRADLE_APK_OUTPUT_PATH]} #{apk_path}") + end + + if deploy + # Upload to Firebase App Distribution + firebase_app_distribution( + app: ENV.fetch('ANDROID_FIREBASE_APP_ID', nil), + service_credentials_json: ENV.fetch('FIREBASE_CREDENTIALS_JSON', nil), + android_artifact_path: apk_path, + android_artifact_type: "APK", + groups: "stream-testers" + ) + else + UI.message("Skipping Firebase upload! (deploy: #{deploy})") + end + end +end + ########################## ###### Common lanes ###### ########################## diff --git a/examples/SampleApp/package.json b/examples/SampleApp/package.json index 5da8d63f2a..8af1d0de86 100644 --- a/examples/SampleApp/package.json +++ b/examples/SampleApp/package.json @@ -20,7 +20,11 @@ "release-next": "echo \"Skipping next release for SampleApp\"", "test:unit": "echo \"Skipping unit tests for SampleApp\"", "clean": "watchman watch-del-all && yarn cache clean && rm -rf ios/build && pod cache clean --all && rm -rf android/build && cd android && ./gradlew clean && cd -", - "clean-all": "yarn clean && rm -rf node_modules && rm -rf ios/Pods && rm -rf vendor && bundle install && yarn install && cd ios && bundle exec pod install && cd -" + "clean-all": "yarn clean && rm -rf node_modules && rm -rf ios/Pods && rm -rf vendor && bundle install && yarn install && cd ios && bundle exec pod install && cd -", + "fastlane:android-build": "bundle exec fastlane android firebase_build_and_upload deploy:false", + "fastlane:android-deploy": "bundle exec fastlane android firebase_build_and_upload deploy:true", + "fastlane:ios-build": "bundle exec fastlane ios deploy_to_testflight_qa deploy:false", + "fastlane:ios-deploy": "bundle exec fastlane ios deploy_to_testflight_qa deploy:true" }, "dependencies": { "@emoji-mart/data": "^1.2.1",