From b9ee930aab7f6ca109b2e90fd0233665f2d79516 Mon Sep 17 00:00:00 2001 From: laszlo-domonkos <85620991+laszlo-domonkos@users.noreply.github.com> Date: Tue, 21 Nov 2023 20:04:56 +0100 Subject: [PATCH] NEVISACCESSAPP-5381: Fixed Android deep link configuration (#26) --- .github/workflows/publish_android.yml | 3 +- README.md | 38 ++++++ android/Gemfile.lock | 89 +++++++------- android/app/build.gradle | 2 +- android/app/src/debug/AndroidManifest.xml | 8 -- android/app/src/main/AndroidManifest.xml | 8 +- android/fastlane/Fastfile | 56 +++++---- android/fastlane/README.md | 2 + android/fastlane/actions/modify_file.rb | 102 +++++++++++++++ .../fastlane/actions/modify_gradle_file.rb | 116 ------------------ 10 files changed, 227 insertions(+), 197 deletions(-) delete mode 100644 android/app/src/debug/AndroidManifest.xml create mode 100644 android/fastlane/actions/modify_file.rb delete mode 100644 android/fastlane/actions/modify_gradle_file.rb diff --git a/.github/workflows/publish_android.yml b/.github/workflows/publish_android.yml index 7490937..963c2b8 100644 --- a/.github/workflows/publish_android.yml +++ b/.github/workflows/publish_android.yml @@ -110,5 +110,6 @@ jobs: lane: 'main' subdirectory: 'android' options: '{ "version": "${{ inputs.version }}", - "build_number": "${{ inputs.build-number }}" + "build_number": "${{ inputs.build-number }}", + "host_name": "${{ secrets.HOST_NAME }}" }' \ No newline at end of file diff --git a/README.md b/README.md index 54cff54..6443b76 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,44 @@ The example apps are supporting two kinds of configuration: `authenticationCloud To change the configuration open the [getit_root.dart](lib/getit_root.dart) file which describes the dependency injection related configuration using the `get_it` dart package. The `environment` parameter should be changed to one of the values already mentioned. +#### Android Manifest XML + +The example applications handle deep links and web links those contain a valid `dispatchTokenResponse` query parameter of an out-of-band operation. The related configuration located in the [AndroidManifest.xml](android/app/src/main/AndroidManifest.xml) for [MainActivity](android/app/src/main/kotlin/ch/nevis/nevis_mobile_authentication_sdk_example_app_flutter/MainActivity.kt) with action `android.intent.action.VIEW`. + +##### Web links + +Change the `myinstance.mauth.nevis.cloud` host value in the following `intent-filter` with the right host information of your environment. + +```xml + + + + + + + + + +``` + +##### Deep links + +Change the `nevisaccess` scheme value in the following `intent-filter` with the right scheme information of your environment. + +```xml + + + + + + + + +``` + +> [!NOTE] +> For more information about deep links, web links visit the official [Android guide](https://developer.android.com/training/app-links). + ### Build Now you're ready to build the example app by running: diff --git a/android/Gemfile.lock b/android/Gemfile.lock index 3220a1d..4e6bb44 100644 --- a/android/Gemfile.lock +++ b/android/Gemfile.lock @@ -3,25 +3,25 @@ GEM specs: CFPropertyList (3.0.6) rexml - addressable (2.8.1) + addressable (2.8.5) public_suffix (>= 2.0.2, < 6.0) artifactory (3.0.15) atomos (0.1.3) aws-eventstream (1.2.0) - aws-partitions (1.708.0) - aws-sdk-core (3.170.0) + aws-partitions (1.854.0) + aws-sdk-core (3.187.1) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.5) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.62.0) - aws-sdk-core (~> 3, >= 3.165.0) + aws-sdk-kms (1.72.0) + aws-sdk-core (~> 3, >= 3.184.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.119.0) - aws-sdk-core (~> 3, >= 3.165.0) + aws-sdk-s3 (1.137.0) + aws-sdk-core (~> 3, >= 3.181.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.4) - aws-sigv4 (1.5.2) + aws-sigv4 (~> 1.6) + aws-sigv4 (1.6.1) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) claide (1.1.0) @@ -30,13 +30,12 @@ GEM commander (4.6.0) highline (~> 2.0.0) declarative (0.0.20) - digest-crc (0.6.4) + digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) - domain_name (0.5.20190701) - unf (>= 0.0.5, < 1.0.0) + domain_name (0.6.20231109) dotenv (2.8.1) emoji_regex (3.2.3) - excon (0.99.0) + excon (0.104.0) faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -65,8 +64,8 @@ GEM faraday-retry (1.0.3) faraday_middleware (1.2.0) faraday (~> 1.0) - fastimage (2.2.6) - fastlane (2.211.0) + fastimage (2.2.7) + fastlane (2.217.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -87,10 +86,11 @@ GEM google-apis-playcustomapp_v1 (~> 0.1) google-cloud-storage (~> 1.31) highline (~> 2.0) + http-cookie (~> 1.0.5) json (< 3.0.0) jwt (>= 2.1.0, < 3) mini_magick (>= 4.9.4, < 5.0.0) - multipart-post (~> 2.0.0) + multipart-post (>= 2.0.0, < 3.0.0) naturally (~> 2.2) optparse (~> 0.1.1) plist (>= 3.1.0, < 4.0.0) @@ -98,7 +98,7 @@ GEM security (= 0.1.3) simctl (~> 1.6.3) terminal-notifier (>= 2.0.0, < 3.0.0) - terminal-table (>= 1.4.5, < 2.0.0) + terminal-table (~> 3) tty-screen (>= 0.6.3, < 1.0.0) tty-spinner (>= 0.8.0, < 1.0.0) word_wrap (~> 1.0.0) @@ -107,9 +107,9 @@ GEM xcpretty-travis-formatter (>= 0.0.3) fastlane-plugin-firebase_app_distribution (0.5.0) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.33.0) - google-apis-core (>= 0.9.1, < 2.a) - google-apis-core (0.11.0) + google-apis-androidpublisher_v3 (0.53.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-core (0.11.2) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -118,30 +118,29 @@ GEM retriable (>= 2.0, < 4.a) rexml webrick - google-apis-iamcredentials_v1 (0.16.0) - google-apis-core (>= 0.9.1, < 2.a) - google-apis-playcustomapp_v1 (0.12.0) - google-apis-core (>= 0.9.1, < 2.a) - google-apis-storage_v1 (0.19.0) - google-apis-core (>= 0.9.0, < 2.a) + google-apis-iamcredentials_v1 (0.17.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-playcustomapp_v1 (0.13.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-storage_v1 (0.29.0) + google-apis-core (>= 0.11.0, < 2.a) google-cloud-core (1.6.0) google-cloud-env (~> 1.0) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) - google-cloud-errors (1.3.0) - google-cloud-storage (1.44.0) + google-cloud-errors (1.3.1) + google-cloud-storage (1.45.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.19.0) + google-apis-storage_v1 (~> 0.29.0) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.3.0) + googleauth (1.8.1) faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) - memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) @@ -151,30 +150,29 @@ GEM httpclient (2.8.3) jmespath (1.6.2) json (2.6.3) - jwt (2.7.0) - memoist (0.16.2) + jwt (2.7.1) mini_magick (4.12.0) - mini_mime (1.1.2) + mini_mime (1.1.5) multi_json (1.15.0) - multipart-post (2.0.0) + multipart-post (2.3.0) nanaimo (0.3.0) naturally (2.2.1) optparse (0.1.1) os (1.1.4) - plist (3.6.0) - public_suffix (5.0.1) - rake (13.0.6) + plist (3.7.0) + public_suffix (5.0.4) + rake (13.1.0) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.5) + rexml (3.2.6) rouge (2.0.7) ruby2_keywords (0.0.5) rubyzip (2.3.2) security (0.1.3) - signet (0.17.0) + signet (0.18.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) @@ -183,21 +181,18 @@ GEM CFPropertyList naturally terminal-notifier (2.0.0) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) trailblazer-option (0.1.2) tty-cursor (0.7.1) tty-screen (0.8.1) tty-spinner (0.9.3) tty-cursor (~> 0.7) uber (0.1.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.8.2) - unicode-display_width (1.8.0) + unicode-display_width (2.5.0) webrick (1.8.1) word_wrap (1.0.0) - xcodeproj (1.22.0) + xcodeproj (1.23.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) diff --git a/android/app/build.gradle b/android/app/build.gradle index db72fc2..51d914d 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -30,7 +30,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 33 + compileSdk 33 compileOptions { sourceCompatibility JavaVersion.VERSION_11 targetCompatibility JavaVersion.VERSION_11 diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index bf8845c..0000000 --- a/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index d4ed62b..a69d25c 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,11 +1,15 @@ + + + + + android:host="myinstance.mauth.nevis.cloud" /> diff --git a/android/fastlane/Fastfile b/android/fastlane/Fastfile index 3402050..41aec74 100644 --- a/android/fastlane/Fastfile +++ b/android/fastlane/Fastfile @@ -9,6 +9,8 @@ root_dir = File.expand_path(File.join(File.dirname(__FILE__), "../")) signing_configs_gradle = File.join(root_dir, "app/signing_configs.gradle") apk_path = File.join(root_dir, "../build/app/outputs/flutter-apk/app-debug.apk") display_name = "Nevis Mobile Authentication SDK Example App Flutter Android" +android_manifest = File.join(root_dir, "app/src/main/AndroidManifest.xml") +build_gradle = File.join(root_dir, "app/build.gradle") def report_on_success(message) slack( @@ -37,37 +39,47 @@ end platform :android do desc "Build and distribute the application" - desc "#### Options" - desc " * **`version`**: The version of the application." - desc " * **`build_number`**: The build number of the application." - desc "" + desc "#### Options" + desc " * **`version`**: The version of the application." + desc " * **`build_number`**: The build number of the application." + desc " * **`host_name`**: The host name to be used in AndroidManifest.xml for deep link configuration." + desc "" lane :main do |options| begin - version = options[:version] - build_number = options[:build_number] + version = options[:version] + build_number = options[:build_number] UI.message("Distributing #{display_name} #{version} (#{build_number}) 📦") + host_name = options[:host_name] + modify_file( + file_path: android_manifest, + old_value: "android:host=\"myinstance.mauth.nevis.cloud\"", + new_value: "android:host=\"#{host_name}.mauth.nevis.cloud\"" + ) + sh("echo \"#{ENV["SIGNING_CONFIGS"]}\" > #{signing_configs_gradle}") - modify_gradle_file( - constant: "signingConfig", - value: "signingConfigs.signing", - ) + modify_file( + file_path: build_gradle, + old_value: "signingConfig signingConfigs.debug", + new_value: "signingConfig signingConfigs.signing", + ) - modify_gradle_file( - constant: "apply plugin: 'kotlin-android'", - value: "apply from: 'signing_configs.gradle'", - mode: 'append' - ) + modify_file( + file_path: build_gradle, + old_value: "android {", + new_value: "apply from: 'signing_configs.gradle'\n", + mode: 'prepend' + ) - sh('flutter build apk --debug') + sh('flutter build apk --debug') - firebase_app_distribution( - app: ENV["FIREBASE_APP_ID_ANDROID"], - apk_path: apk_path, - groups: 'developers, internal-testers, presales' - ) - report_on_success("#{display_name} build is completed: #{version} (#{build_number}) ✅") + firebase_app_distribution( + app: ENV["FIREBASE_APP_ID_ANDROID"], + apk_path: apk_path, + groups: 'developers, internal-testers, presales' + ) + report_on_success("#{display_name} build is completed: #{version} (#{build_number}) ✅") rescue => exception report_on_error("#{display_name} build failed ❌", exception) end diff --git a/android/fastlane/README.md b/android/fastlane/README.md index 0a2484f..a1e6e51 100644 --- a/android/fastlane/README.md +++ b/android/fastlane/README.md @@ -29,6 +29,8 @@ Build and distribute the application * **`build_number`**: The build number of the application. + * **`host_name`**: The host name to be used in AndroidManifest.xml for deep link configuration. + ---- diff --git a/android/fastlane/actions/modify_file.rb b/android/fastlane/actions/modify_file.rb new file mode 100644 index 0000000..d370050 --- /dev/null +++ b/android/fastlane/actions/modify_file.rb @@ -0,0 +1,102 @@ +require 'tempfile' +require 'fileutils' + +module Fastlane + module Actions + class ModifyFileAction < Action + def self.run(params) + file_path ||= params[:file_path] + old_value = params[:old_value] + new_value = params[:new_value] + mode ||= params[:mode] + + UI.message(" Modifying file (#{file_path})!") + modify(file_path, old_value, new_value, mode) + end + + def self.modify(path, old_value, new_value, mode) + if !File.file?(path) + raise "No file exist at path: (#{File.expand_path(path)})!" + end + + begin + temp_file = Tempfile.new('fastlaneModifyFile') + File.open(path, 'r') do |file| + file.each_line do |line| + if line.include? old_value + if mode == "replace" + line.replace line.sub(old_value, new_value) + temp_file.puts line + elsif mode == "append" + temp_file.puts line + temp_file.puts new_value + elsif mode == "prepend" + temp_file.puts new_value + temp_file.puts line + end + else + temp_file.puts line + end + end + file.close + end + temp_file.rewind + temp_file.close + FileUtils.mv(temp_file.path, path) + temp_file.unlink + rescue + raise 'Modifying file failed!' + end + end + + def self.description + "Modify file of your Android project." + end + + def self.available_options + [ + FastlaneCore::ConfigItem.new(key: :file_path, + description: "The path to the file to be modified", + optional: false, + type: String), + FastlaneCore::ConfigItem.new(key: :old_value, + description: "The old value whose to be replaced, appended after or prepended before with new value", + optional: false, + type: String), + FastlaneCore::ConfigItem.new(key: :new_value, + description: "The new value", + optional: false, + type: String), + FastlaneCore::ConfigItem.new(key: :mode, + description: "The working mode. Possible values are replace, append or prepend (default: replace)", + optional: true, + type: String, + default_value:"replace"), + ] + end + + def self.author + "Nevis Security AG" + end + + def self.is_supported?(platform) + [:android].include? platform + end + + def self.example_code + [ + modify_file( + file_path: file, + old_value: "", + new_value: "", + mode: "append" + ) + ] + end + + def self.category + :project + end + end + end +end \ No newline at end of file diff --git a/android/fastlane/actions/modify_gradle_file.rb b/android/fastlane/actions/modify_gradle_file.rb deleted file mode 100644 index 0e76e73..0000000 --- a/android/fastlane/actions/modify_gradle_file.rb +++ /dev/null @@ -1,116 +0,0 @@ -require 'tempfile' -require 'fileutils' - -module Fastlane - module Actions - class ModifyGradleFileAction < Action - def self.run(params) - gradle_file_path ||= params[:gradle_file_path] - constant = params[:constant] - value = params[:value] - mode ||= params[:mode] - - if gradle_file_path != nil - UI.message(" Using gradle file (#{gradle_file_path})!") - modify(gradle_file_path, constant, value, mode) - else - app_folder_name ||= params[:app_folder_name] - UI.message("Using project folder `#{app_folder_name}`!") - - Dir.glob("**/#{app_folder_name}/build.gradle") do |path| - modify(path, constant, value, mode) - end - end - end - - def self.modify(path, constant_name, constant_value, mode) - if !File.file?(path) - raise "No file exist at path: (#{path})!" - end - - begin - temp_file = Tempfile.new('fastlaneModifyGradleFile') - File.open(path, 'r') do |file| - file.each_line do |line| - if line.include? constant_name - if mode == "replace" - components = line.strip.split(' ') - current_value = components[components.length-1].tr("\"","") - line.replace line.sub(current_value, constant_value) - temp_file.puts line - elsif mode == "append" - temp_file.puts line - temp_file.puts constant_value - end - else - temp_file.puts line - end - end - file.close - end - temp_file.rewind - temp_file.close - FileUtils.mv(temp_file.path, path) - temp_file.unlink - rescue - raise 'Modifying gradle file failed!' - end - end - - def self.description - "Modify gradle file of your Android project." - end - - def self.available_options - [ - FastlaneCore::ConfigItem.new(key: :app_folder_name, - description: "The name of the application source folder in the Android project (default: app)", - optional: true, - type: String, - default_value:"app"), - FastlaneCore::ConfigItem.new(key: :gradle_file_path, - description: "The relative path to the gradle file containing the constant parameter (default:app/build.gradle)", - optional: true, - type: String, - default_value: nil), - FastlaneCore::ConfigItem.new(key: :constant, - description: "The constant whose value is to be replaced or appended after", - optional: false, - type: String), - FastlaneCore::ConfigItem.new(key: :value, - description: "The new value", - optional: false, - type: String), - FastlaneCore::ConfigItem.new(key: :mode, - description: "The working mode. Possible values are replace or append (default: replace)", - optional: true, - type: String, - default_value:"replace"), - ] - end - - def self.author - "Nevis Security AG" - end - - def self.is_supported?(platform) - [:android].include? platform - end - - def self.example_code - [ - modify_gradle_file( - gradle_file_path: file, - constant: "", - value: "", - mode: "append" - ) - ] - end - - def self.category - :project - end - end - end -end \ No newline at end of file