pindo 4.6.9 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pindo/base/aeshelper.rb +48 -2
  3. data/lib/pindo/base/funlog.rb +89 -0
  4. data/lib/pindo/base/githelper.rb +30 -12
  5. data/lib/pindo/base/plaininformative.rb +3 -0
  6. data/lib/pindo/base/standarderror.rb +1 -0
  7. data/lib/pindo/base/xcodeconst.rb +251 -0
  8. data/lib/pindo/client/applovinclient.rb +6 -3
  9. data/lib/pindo/client/aws3sclient.rb +33 -46
  10. data/lib/pindo/client/bossclient.rb +1 -1
  11. data/lib/pindo/client/pgyerclient.rb +78 -14
  12. data/lib/pindo/command/appstore/iap.rb +43 -0
  13. data/lib/pindo/command/appstore/itcapp.rb +41 -0
  14. data/lib/pindo/command/appstore/metadata.rb +43 -0
  15. data/lib/pindo/command/appstore/screenshots.rb +43 -0
  16. data/lib/pindo/command/appstore/upload.rb +40 -0
  17. data/lib/pindo/command/appstore.rb +17 -0
  18. data/lib/pindo/command/deploy/build.rb +109 -0
  19. data/lib/pindo/{deploy → command/deploy}/bundleid.rb +1 -1
  20. data/lib/pindo/command/deploy/cert.rb +179 -0
  21. data/lib/pindo/command/deploy/configproj.rb +105 -0
  22. data/lib/pindo/{deploy → command/deploy}/getitcinfo.rb +1 -1
  23. data/lib/pindo/{deploy → command/deploy}/iap.rb +30 -9
  24. data/lib/pindo/{deploy → command/deploy}/itcapp.rb +0 -1
  25. data/lib/pindo/{deploy → command/deploy}/itcinfo.rb +2 -3
  26. data/lib/pindo/{deploy → command/deploy}/pem.rb +3 -2
  27. data/lib/pindo/{deploy → command/deploy}/resign.rb +14 -63
  28. data/lib/pindo/command/deploy.rb +44 -0
  29. data/lib/pindo/{dev → command/dev}/autobuild.rb +17 -80
  30. data/lib/pindo/{dev → command/dev}/autoresign.rb +17 -64
  31. data/lib/pindo/{dev → command/dev}/createbuild.rb +0 -2
  32. data/lib/pindo/{dev → command/dev}/debug.rb +6 -2
  33. data/lib/pindo/command/dev/pgyercert.rb +75 -0
  34. data/lib/pindo/command/dev.rb +25 -0
  35. data/lib/pindo/command/env.rb +17 -0
  36. data/lib/pindo/{ipa → command/ipa}/autoresign.rb +18 -70
  37. data/lib/pindo/{ipa → command/ipa}/import.rb +47 -102
  38. data/lib/pindo/{ipa → command/ipa}/output.rb +38 -135
  39. data/lib/pindo/command/ipa.rb +16 -0
  40. data/lib/pindo/{lib → command/lib}/update.rb +19 -10
  41. data/lib/pindo/command/lib.rb +16 -0
  42. data/lib/pindo/{pgyer → command/pgyer}/apptest.rb +7 -29
  43. data/lib/pindo/{pgyer → command/pgyer}/comment.rb +7 -30
  44. data/lib/pindo/{pgyer → command/pgyer}/download.rb +35 -30
  45. data/lib/pindo/{pgyer → command/pgyer}/login.rb +3 -4
  46. data/lib/pindo/command/pgyer/resign.rb +111 -0
  47. data/lib/pindo/command/pgyer/upload.rb +123 -0
  48. data/lib/pindo/command/pgyer.rb +18 -0
  49. data/lib/pindo/{repo.rb → command/repo.rb} +4 -4
  50. data/lib/pindo/{utils → command/utils}/applovin.rb +43 -33
  51. data/lib/pindo/{utils → command/utils}/boss.rb +3 -3
  52. data/lib/pindo/command/utils/icon.rb +81 -0
  53. data/lib/pindo/{utils → command/utils}/renewproj.rb +1 -0
  54. data/lib/pindo/command/utils.rb +26 -0
  55. data/lib/pindo/command.rb +23 -26
  56. data/lib/pindo/module/build/swarkhelper.rb +95 -0
  57. data/lib/pindo/module/cert/certhelper.rb +176 -0
  58. data/lib/pindo/module/cert/keychainhelper.rb +138 -0
  59. data/lib/pindo/module/{pemcreate.rb → cert/pemhelper.rb} +3 -1
  60. data/lib/pindo/module/cert/provisioninghelper.rb +137 -0
  61. data/lib/pindo/module/cert/xcodecerthelper.rb +301 -0
  62. data/lib/pindo/module/{pgyerhelper.rb → pgyer/pgyerhelper.rb} +246 -35
  63. data/lib/pindo/module/xcode/xcodeappconfig.rb +188 -0
  64. data/lib/pindo/module/xcode/xcodebuildconfig.rb +12 -0
  65. data/lib/pindo/module/xcode/xcodebuildhelper.rb +312 -0
  66. data/lib/pindo/module/xcode/xcoderesconstant.rb +248 -0
  67. data/lib/pindo/module/xcode/xcodereshandler.rb +198 -0
  68. data/lib/pindo/module/xcode/xcodereshelper.rb +120 -0
  69. data/lib/pindo/options/appconfigoptions.rb +1 -0
  70. data/lib/pindo/options/deployoptions.rb +38 -41
  71. data/lib/pindo/version.rb +1 -1
  72. metadata +109 -97
  73. data/lib/pindo/deploy/Fastfile +0 -233
  74. data/lib/pindo/deploy/build.rb +0 -167
  75. data/lib/pindo/deploy/cert.rb +0 -508
  76. data/lib/pindo/deploy/configproj.rb +0 -89
  77. data/lib/pindo/deploy.rb +0 -44
  78. data/lib/pindo/dev.rb +0 -23
  79. data/lib/pindo/env/flutter.rb +0 -59
  80. data/lib/pindo/env/flutter.sh +0 -116
  81. data/lib/pindo/env.rb +0 -17
  82. data/lib/pindo/ipa.rb +0 -22
  83. data/lib/pindo/lib.rb +0 -18
  84. data/lib/pindo/module/buildconfighelper.rb +0 -13
  85. data/lib/pindo/module/buildhelper.rb +0 -76
  86. data/lib/pindo/module/config_project.sh +0 -143
  87. data/lib/pindo/module/configprojhelper.rb +0 -631
  88. data/lib/pindo/module/icon_contents.json +0 -116
  89. data/lib/pindo/module/imessage_icon.json +0 -91
  90. data/lib/pindo/module/imgset_contents.json +0 -21
  91. data/lib/pindo/module/launchimg_contents.json +0 -21
  92. data/lib/pindo/module/xcodebuildpre.rb +0 -258
  93. data/lib/pindo/pgyer/upload.rb +0 -234
  94. data/lib/pindo/pgyer.rb +0 -17
  95. data/lib/pindo/utils/icon.rb +0 -91
  96. data/lib/pindo/utils/icon.sh +0 -133
  97. data/lib/pindo/utils/podindex.rb +0 -56
  98. data/lib/pindo/utils/podindex.sh +0 -30
  99. data/lib/pindo/utils.rb +0 -29
  100. /data/lib/pindo/{deploy → command/deploy}/check.rb +0 -0
  101. /data/lib/pindo/{deploy → command/deploy}/confusecode.rb +0 -0
  102. /data/lib/pindo/{deploy → command/deploy}/confuseproj.rb +0 -0
  103. /data/lib/pindo/{deploy → command/deploy}/fabric.rb +0 -0
  104. /data/lib/pindo/{deploy → command/deploy}/initconfig.rb +0 -0
  105. /data/lib/pindo/{deploy → command/deploy}/pullconfig.rb +0 -0
  106. /data/lib/pindo/{deploy → command/deploy}/pushconfig.rb +0 -0
  107. /data/lib/pindo/{deploy → command/deploy}/quswark.rb +0 -0
  108. /data/lib/pindo/{deploy → command/deploy}/quswauth.rb +0 -0
  109. /data/lib/pindo/{deploy → command/deploy}/reportbug.rb +0 -0
  110. /data/lib/pindo/{deploy → command/deploy}/tag.rb +0 -0
  111. /data/lib/pindo/{deploy → command/deploy}/updateconfig.rb +0 -0
  112. /data/lib/pindo/{deploy → command/deploy}/uploadipa.rb +0 -0
  113. /data/lib/pindo/{dev → command/dev}/confusecode.rb +0 -0
  114. /data/lib/pindo/{dev → command/dev}/confuseproj.rb +0 -0
  115. /data/lib/pindo/{dev → command/dev}/pub.rb +0 -0
  116. /data/lib/pindo/{dev → command/dev}/renewcert.rb +0 -0
  117. /data/lib/pindo/{env → command/env}/dreamstudio.rb +0 -0
  118. /data/lib/pindo/{env → command/env}/quarkenv.rb +0 -0
  119. /data/lib/pindo/{env → command/env}/swarkenv.rb +0 -0
  120. /data/lib/pindo/{env → command/env}/workhard.rb +0 -0
  121. /data/lib/pindo/{lib → command/lib}/forcepush.rb +0 -0
  122. /data/lib/pindo/{lib → command/lib}/lint.rb +0 -0
  123. /data/lib/pindo/{lib → command/lib}/push.rb +0 -0
  124. /data/lib/pindo/{repo → command/repo}/clone.rb +0 -0
  125. /data/lib/pindo/{repo → command/repo}/create.rb +0 -0
  126. /data/lib/pindo/{repo → command/repo}/login.rb +0 -0
  127. /data/lib/pindo/{repo → command/repo}/search.rb +0 -0
  128. /data/lib/pindo/{setup.rb → command/setup.rb} +0 -0
  129. /data/lib/pindo/{upgrade.rb → command/upgrade.rb} +0 -0
  130. /data/lib/pindo/{utils → command/utils}/clearcert.rb +0 -0
  131. /data/lib/pindo/{utils → command/utils}/device.rb +0 -0
  132. /data/lib/pindo/{utils → command/utils}/tgate.rb +0 -0
  133. /data/lib/pindo/{utils → command/utils}/xcassets.rb +0 -0
  134. /data/lib/pindo/{utils → command/utils}/xcassets.sh +0 -0
  135. /data/lib/pindo/module/{appstore_in_app_purchase.rb → appstore/appstore_in_app_purchase.rb} +0 -0
  136. /data/lib/pindo/module/{appstore_metadata_connect_api_helper.rb → appstore/appstore_metadata_connect_api_helper.rb} +0 -0
  137. /data/lib/pindo/module/{appstore_metadata_fastlane_helper.rb → appstore/appstore_metadata_fastlane_helper.rb} +0 -0
  138. /data/lib/pindo/module/{iap_tier.json → appstore/iap_tier.json} +0 -0
  139. /data/lib/pindo/module/{commonconfuseproj.rb → build/commonconfuseproj.rb} +0 -0
  140. /data/lib/pindo/module/{xcodehelper.rb → xcode/xcodehelper.rb} +0 -0
@@ -0,0 +1,138 @@
1
+
2
+ require 'open3'
3
+ require 'security'
4
+
5
+ module Pindo
6
+
7
+ module KeychainHelper
8
+
9
+ def self.import_file(path, keychain_path, keychain_password: nil, certificate_password: "", skip_set_partition_list: false, output: false)
10
+ puts "Could not find file '#{path}'" unless File.exist?(path)
11
+
12
+ password_part = " -P #{certificate_password.shellescape}"
13
+
14
+ command = "security import #{path.shellescape} -k '#{keychain_path.shellescape}'"
15
+ command << password_part
16
+ command << " -T /usr/bin/codesign" # to not be asked for permission when running a tool like `gym` (before Sierra)
17
+ command << " -T /usr/bin/security"
18
+ command << " -T /usr/bin/productbuild" # to not be asked for permission when using an installer cert for macOS
19
+ command << " -T /usr/bin/productsign" # to not be asked for permission when using an installer cert for macOS
20
+ command << " 1> /dev/null" unless output
21
+
22
+ sensitive_command = command.gsub(password_part, " -P ********")
23
+ UI.command(sensitive_command) if output
24
+ Open3.popen3(command) do |stdin, stdout, stderr, thrd|
25
+ UI.command_output(stdout.read.to_s) if output
26
+
27
+ # Set partition list only if success since it can be a time consuming process if a lot of keys are installed
28
+ if thrd.value.success? && !skip_set_partition_list
29
+ keychain_password ||= resolve_keychain_password(keychain_path)
30
+ set_partition_list(path, keychain_path, keychain_password: keychain_password, output: output)
31
+ else
32
+ # Output verbose if file is already installed since not an error otherwise we will show the whole error
33
+ err = stderr.read.to_s.strip
34
+ if err.include?("SecKeychainItemImport") && err.include?("The specified item already exists in the keychain")
35
+ # UI.verbose("'#{File.basename(path)}' is already installed on this machine")
36
+ else
37
+ raise Informative, err
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def self.help_backticks(command, print: true)
44
+ # UI.command(command) if print
45
+ result = `#{command}`
46
+ # UI.command_output(result) if print
47
+ return result
48
+ end
49
+
50
+ def self.set_partition_list(path, keychain_path, keychain_password: nil, output: false)
51
+ # When security supports partition lists, also add the partition IDs
52
+ # See https://openradar.appspot.com/28524119
53
+ if help_backticks('security -h | grep set-key-partition-list', print: false).length > 0
54
+ password_part = " -k #{keychain_password.to_s.shellescape}"
55
+
56
+ command = "security set-key-partition-list"
57
+ command << " -S apple-tool:,apple:,codesign:"
58
+ command << " -s" # This is a needed in Catalina to prevent "security: SecKeychainItemCopyAccess: A missing value was detected."
59
+ command << password_part
60
+ command << " #{keychain_path.shellescape}"
61
+ command << " 1> /dev/null" # always disable stdout. This can be very verbose, and leak potentially sensitive info
62
+
63
+ # Showing loading indicator as this can take some time if a lot of keys installed
64
+ # Helper.show_loading_indicator("Setting key partition list... (this can take a minute if there are a lot of keys installed)")
65
+
66
+ # Strip keychain password from command output
67
+ sensitive_command = command.gsub(password_part, " -k ********")
68
+ UI.command(sensitive_command) if output
69
+ Open3.popen3(command) do |stdin, stdout, stderr, thrd|
70
+ unless thrd.value.success?
71
+ err = stderr.read.to_s.strip
72
+
73
+ # Inform user when no/wrong password was used as its needed to prevent UI permission popup from Xcode when signing
74
+ if err.include?("SecKeychainItemSetAccessWithPassword")
75
+ keychain_name = File.basename(keychain_path, ".*")
76
+ Security::InternetPassword.delete(server: server_name(keychain_name))
77
+
78
+ # UI.important("")
79
+ # UI.important("Could not configure imported keychain item (certificate) to prevent UI permission popup when code signing\n" \
80
+ # "Check if you supplied the correct `keychain_password` for keychain: `#{keychain_path}`\n" \
81
+ # "#{err}")
82
+ # UI.important("")
83
+ # UI.important("Please look at the following docs to see how to set a keychain password:")
84
+ # UI.important(" - https://docs.fastlane.tools/actions/sync_code_signing")
85
+ # UI.important(" - https://docs.fastlane.tools/actions/get_certificates")
86
+ puts "密码错误"
87
+ else
88
+ raise Informative, err
89
+ end
90
+ end
91
+ end
92
+
93
+ # Hiding after Open3 finishes
94
+ # Helper.hide_loading_indicator
95
+
96
+ end
97
+ end
98
+
99
+ # https://github.com/fastlane/fastlane/issues/14196
100
+ # Keychain password is needed to set the partition list to
101
+ # prevent Xcode from prompting dialog for keychain password when signing
102
+ # 1. Uses keychain password from login keychain if found
103
+ # 2. Prompts user for keychain password and stores it in login keychain for user later
104
+ def self.resolve_keychain_password(keychain_path)
105
+ keychain_name = File.basename(keychain_path, ".*")
106
+ server = server_name(keychain_name)
107
+
108
+ # Attempt to find password in keychain for keychain
109
+ item = Security::InternetPassword.find(server: server)
110
+ if item
111
+ keychain_password = item.password
112
+ # UI.important("Using keychain password from keychain item #{server} in #{keychain_path}")
113
+ end
114
+
115
+ if keychain_password.nil?
116
+ # if UI.interactive?
117
+ # UI.important("Enter the password for #{keychain_path}")
118
+ # UI.important("This passphrase will be stored in your local keychain with the name #{server} and used in future runs")
119
+ # UI.important("This prompt can be avoided by specifying the 'keychain_password' option or 'MATCH_KEYCHAIN_PASSWORD' environment variable")
120
+ keychain_password = FastlaneCore::Helper.ask_password(message: "Password for #{keychain_name} keychain: ", confirm: true, confirmation_message: "Type password for #{keychain_name} keychain again: ")
121
+ Security::InternetPassword.add(server, "", keychain_password)
122
+ # else
123
+ # UI.important("Keychain password for #{keychain_path} was not specified and not found in your keychain. Specify the 'keychain_password' option to prevent the UI permission popup when code signing")
124
+ # keychain_password = ""
125
+ # end
126
+ end
127
+
128
+ return keychain_password
129
+ end
130
+
131
+ # server name used for accessing the macOS keychain
132
+ def self.server_name(keychain_name)
133
+ ["fastlane", "keychain", keychain_name].join("_")
134
+ end
135
+
136
+ private_class_method :server_name
137
+ end
138
+ end
@@ -1,6 +1,8 @@
1
1
 
2
2
  module Pindo
3
- module Pemcreate
3
+
4
+ module PemHelper
5
+
4
6
  def create_certificate(bundle_id:nil, type:"prod", output_path:"")
5
7
 
6
8
  if bundle_id.empty? || output_path.empty?
@@ -0,0 +1,137 @@
1
+ require 'plist'
2
+ require 'json'
3
+
4
+ module Pindo
5
+ class Provisioninghelper
6
+ class << self
7
+ # @return (Hash) The hash with the data of the provisioning profile
8
+ # @example
9
+ # {"AppIDName"=>"My App Name",
10
+ # "ApplicationIdentifierPrefix"=>["5A997XSAAA"],
11
+ # "CreationDate"=>#<DateTime: 2015-05-24T20:38:03+00:00 ((2457167j,74283s,0n),+0s,2299161j)>,
12
+ # "DeveloperCertificates"=>[#<StringIO:0x007f944b9666f8>],
13
+ # "Entitlements"=>
14
+ # {"keychain-access-groups"=>["5A997XSAAA.*"],
15
+ # "get-task-allow"=>false,
16
+ # "application-identifier"=>"5A997XAAA.net.sunapps.192",
17
+ # "com.apple.developer.team-identifier"=>"5A997XAAAA",
18
+ # "aps-environment"=>"production",
19
+ # "beta-reports-active"=>true},
20
+ # "ExpirationDate"=>#<DateTime: 2015-11-25T22:45:50+00:00 ((2457352j,81950s,0n),+0s,2299161j)>,
21
+ # "Name"=>"net.sunapps.192 AppStore",
22
+ # "TeamIdentifier"=>["5A997XSAAA"],
23
+ # "TeamName"=>"SunApps GmbH",
24
+ # "TimeToLive"=>185,
25
+ # "UUID"=>"1752e382-53bd-4910-a393-aaa7de0005ad",
26
+ # "Version"=>1}
27
+ def parse(path, keychain_path = nil)
28
+
29
+
30
+ plist = Plist.parse_xml(decode(path, keychain_path))
31
+ # puts JSON.pretty_generate(plist)
32
+ if (plist || []).count > 5
33
+ plist
34
+ else
35
+ raise Informative, "Error parsing provisioning profile at path '#{path}'"
36
+ end
37
+ end
38
+
39
+ # @return [String] The UUID of the given provisioning profile
40
+ def uuid(path, keychain_path = nil)
41
+ parse(path, keychain_path).fetch("UUID")
42
+ end
43
+
44
+ # @return [String] The Name of the given provisioning profile
45
+ def name(path, keychain_path = nil)
46
+ parse(path, keychain_path).fetch("Name")
47
+ end
48
+
49
+ def bundle_id(path, keychain_path = nil)
50
+ profile = parse(path, keychain_path)
51
+ app_id_prefix = profile["ApplicationIdentifierPrefix"].first
52
+ entitlements = profile["Entitlements"]
53
+ app_identifier = entitlements["application-identifier"] || entitlements["com.apple.application-identifier"]
54
+ bundle_id = app_identifier.gsub("#{app_id_prefix}.", "")
55
+ bundle_id
56
+ rescue
57
+ UI.error("Unable to extract the Bundle Id from the provided provisioning profile '#{path}'.")
58
+ end
59
+
60
+ def mac?(path, keychain_path = nil)
61
+ parse(path, keychain_path).fetch("Platform", []).include?('OSX')
62
+ end
63
+
64
+ def profile_filename(path, keychain_path = nil)
65
+ basename = uuid(path, keychain_path)
66
+ basename + profile_extension(path, keychain_path)
67
+ end
68
+
69
+ def profile_extension(path, keychain_path = nil)
70
+ if mac?(path, keychain_path)
71
+ ".provisionprofile"
72
+ else
73
+ ".mobileprovision"
74
+ end
75
+ end
76
+
77
+ def profiles_path
78
+ path = File.expand_path("~") + "/Library/MobileDevice/Provisioning Profiles/"
79
+ # If the directory doesn't exist, create it first
80
+ unless File.directory?(path)
81
+ FileUtils.mkdir_p(path)
82
+ end
83
+
84
+ return path
85
+ end
86
+
87
+ # Installs a provisioning profile for Xcode to use
88
+ def install(path, keychain_path = nil)
89
+
90
+
91
+ destination = File.join(profiles_path, profile_filename(path, keychain_path))
92
+ puts "Installing provisioning profile... #{destination}"
93
+
94
+ if path != destination
95
+ # copy to Xcode provisioning profile directory
96
+ FileUtils.copy(path, destination)
97
+ unless File.exist?(destination)
98
+ raise Informative, "Failed installation of provisioning profile at location: '#{destination}'"
99
+ end
100
+ end
101
+ destination
102
+ end
103
+
104
+ private
105
+
106
+ def isMacOS?
107
+ (/darwin/ =~ RUBY_PLATFORM) != nil
108
+ end
109
+
110
+
111
+ def decode(path, keychain_path = nil)
112
+ require 'tmpdir'
113
+ Dir.mktmpdir('fastlane') do |dir|
114
+ err = "#{dir}/cms.err"
115
+ # we want to prevent the error output to mix up with the standard output because of
116
+ # /dev/null: https://github.com/fastlane/fastlane/issues/6387
117
+ if isMacOS?
118
+ if keychain_path.nil?
119
+ decoded = `security cms -D -i "#{path}" 2> #{err}`
120
+ else
121
+ decoded = `security cms -D -i "#{path}" -k "#{keychain_path.shellescape}" 2> #{err}`
122
+ end
123
+ else
124
+ # `security` only works on Mac, fallback to `openssl`
125
+ # via https://stackoverflow.com/a/14379814/252627
126
+ decoded = `openssl smime -inform der -verify -noverify -in #{path.shellescape} 2> #{err}`
127
+ end
128
+
129
+ if $?.exitstatus != 0
130
+ raise Informative, "Failure to decode #{path}"
131
+ end
132
+ decoded
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,301 @@
1
+
2
+ require 'fileutils'
3
+
4
+ module Pindo
5
+
6
+ module XcodeCertHelper
7
+
8
+ def get_target_name_map
9
+ return {
10
+ "MainTarget" => "bundle_id",
11
+ "Content" => "bundle_id_pushcontent",
12
+ "Service" => "bundle_id_pushservice",
13
+ "Keyboard" => "bundle_id_keyboard",
14
+ "iMessage" => "bundle_id_imessage",
15
+ "Siri" => "bundle_id_siri",
16
+ "SiriUI" => "bundle_id_siriui",
17
+ "Widget" => "bundle_id_widget",
18
+ "Extension" => "bundle_id_extension",
19
+ "ExtensionAd" => "bundle_id_extensionad",
20
+ "ExtensionPorn" => "bundle_id_extensionporn",
21
+ "WatchApp" => "bundle_id_watchapp",
22
+ "WatchAppComplication" => "bundle_id_watchapp_extension"
23
+ }
24
+ end
25
+
26
+ def create_provisioning_info_array(build_type:nil)
27
+
28
+ provisioning_info_array = []
29
+
30
+ bundle_id_map = get_bundle_id_map
31
+
32
+ bundle_id_map.each do |type, bundle_id_temp|
33
+ provisioning_info = {}
34
+ provisioning_info['type'] = type
35
+ provisioning_info['bundle_id'] = bundle_id_temp
36
+ name_temp = Match::Utils.environment_variable_name_profile_name(app_identifier: bundle_id_temp, type: build_type)
37
+ provisioning_info['profile_name'] = ENV[name_temp]
38
+ path_temp = Match::Utils.environment_variable_name_profile_path(app_identifier:bundle_id_temp,type: build_type)
39
+ provisioning_info['profile_path'] = ENV[path_temp]
40
+ signing_identity_key=Match::Utils.environment_variable_name_certificate_name(app_identifier: bundle_id_temp,type: build_type)
41
+ provisioning_info["signing_identity"] = ENV[signing_identity_key]
42
+ team_id_key = Match::Utils.environment_variable_name_team_id(app_identifier: bundle_id_temp,type:build_type)
43
+ provisioning_info["team_id"] = ENV[team_id_key]
44
+ provisioning_info_array << provisioning_info
45
+ end
46
+
47
+
48
+ return provisioning_info_array
49
+ end
50
+
51
+ def config_project_cert(new_proj_name:nil, new_project_dir:nil, cert_type:nil, team_id_vaule:nil, provisioning_info_array:nil)
52
+
53
+
54
+ new_proj_fullname = File.join(new_project_dir, new_proj_name) + ".xcodeproj"
55
+ new_project_obj = Xcodeproj::Project.open(new_proj_fullname)
56
+
57
+ new_project_obj.root_object.build_configuration_list.set_setting('CODE_SIGN_IDENTITY[sdk=iphoneos*]', "Apple Distribution")
58
+ new_project_obj.root_object.build_configuration_list.set_setting('CODE_SIGN_IDENTITY*', "Apple Distribution")
59
+
60
+ if cert_type == "development"
61
+ new_project_obj.root_object.build_configuration_list.set_setting('CODE_SIGN_IDENTITY[sdk=iphoneos*]', "Apple Development")
62
+ new_project_obj.root_object.build_configuration_list.set_setting('CODE_SIGN_IDENTITY*', "Apple Development")
63
+ end
64
+
65
+ new_project_obj.root_object.attributes['TargetAttributes'] = new_project_obj.root_object.attributes['TargetAttributes'] || {}
66
+ target_atts_obj = new_project_obj.root_object.attributes['TargetAttributes']
67
+
68
+ target_map = get_target_name_map
69
+
70
+ new_project_obj.targets.each do |target|
71
+
72
+ provisioning_info = nil
73
+
74
+ if target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application])
75
+ bundle_id_map_key = target_map["MainTarget"]
76
+ provisioning_info = provisioning_info_array.select { |s| s["type"].to_s.eql?(bundle_id_map_key.to_s) }.first
77
+ elsif
78
+ target_map.each do |k, v|
79
+ if target.name.to_s.end_with?(k)
80
+ bundle_id_map_key = v.to_s
81
+ provisioning_info = provisioning_info_array.select { |s| s["type"].to_s.eql?(bundle_id_map_key.to_s) }.first
82
+ end
83
+ end
84
+ end
85
+
86
+ target.build_configurations.each do |config|
87
+ target_atts_obj[target.uuid] = target_atts_obj[target.uuid] || {}
88
+ target_atts_obj[target.uuid]['DevelopmentTeam'] = team_id_vaule
89
+ target_atts_obj[target.uuid]['ProvisioningStyle'] = "Manual"
90
+ config.build_settings['DEVELOPMENT_TEAM'] = team_id_vaule
91
+ config.build_settings['DEVELOPMENT_TEAM[sdk=iphoneos*]'] = team_id_vaule
92
+ config.build_settings['CODE_SIGN_STYLE'] = "Manual"
93
+
94
+ config.build_settings['CODE_SIGN_IDENTITY'] = "Apple Distribution"
95
+ config.build_settings['CODE_SIGN_IDENTITY[sdk=iphoneos*]'] = "Apple Distribution"
96
+
97
+ if cert_type == "development"
98
+ config.build_settings['CODE_SIGN_IDENTITY'] = "Apple Development"
99
+ config.build_settings['CODE_SIGN_IDENTITY[sdk=iphoneos*]'] = "Apple Development"
100
+ end
101
+
102
+ if !provisioning_info.nil?
103
+ config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = provisioning_info["bundle_id"]
104
+ config.build_settings['PROVISIONING_PROFILE_SPECIFIER'] = provisioning_info['profile_name']
105
+ config.build_settings['PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]'] = provisioning_info['profile_name']
106
+
107
+ end
108
+ end
109
+
110
+ end
111
+ new_project_obj.save
112
+
113
+ end
114
+
115
+ def config_infoplist_cert(new_proj_name:nil, new_project_dir:nil, icloud_id:nil, group_id:nil, provisioning_info_array:nil)
116
+
117
+ new_proj_fullname = File.join(new_project_dir, new_proj_name) + ".xcodeproj"
118
+ project_obj = Xcodeproj::Project.open(new_proj_fullname)
119
+ entitlements_plist_path = File.join(new_project_dir, new_proj_name + ".entitlements")
120
+
121
+ project_obj.targets.each do |target|
122
+
123
+ temp_entitlements_file = target.build_configurations.first.build_settings['CODE_SIGN_ENTITLEMENTS']
124
+ if !temp_entitlements_file.nil? && !temp_entitlements_file.empty?
125
+ entitlements_plist_path = File.join(new_project_dir, temp_entitlements_file)
126
+
127
+ if !File.exist?(entitlements_plist_path)
128
+ raise Informative, "Target: #{target.name.to_s} 找不到文件 #{entitlements_plist_path}"
129
+ end
130
+ end
131
+
132
+ temp_info = target.build_configurations.first.build_settings['INFOPLIST_FILE']
133
+ info_plist_path = File.join(new_project_dir, temp_info)
134
+ if target.product_type.to_s.eql?("com.apple.product-type.application") && !File.exist?(info_plist_path)
135
+ raise Informative, "Missing Target #{target.name.to_s} Info.plist!!! #{info_plist_path} Modify Info.plist Error !!!"
136
+ end
137
+
138
+
139
+ if target.product_type.to_s.eql?("com.apple.product-type.application") then
140
+ add_swark_entitlement(entitlements_plist_path:entitlements_plist_path, bundle_id_dict:provisioning_info_array)
141
+ if !icloud_id.nil?
142
+ modify_entitlements_plist(entitlements_plist_path:entitlements_plist_path, icloud_id:icloud_id)
143
+ modify_info_plist_icloud(plist_file_name:info_plist_path, icloud_id:icloud_id)
144
+ else
145
+ modify_info_plist_icloud(plist_file_name:info_plist_path, icloud_id:nil)
146
+ end
147
+ end
148
+ if !group_id.nil?
149
+ modify_entitlements_plist(entitlements_plist_path:entitlements_plist_path, group_id:group_id)
150
+ end
151
+ end
152
+
153
+ end
154
+
155
+ def modify_entitlements_plist(entitlements_plist_path:nil, group_id:nil, icloud_id:nil)
156
+ if File.exist?(entitlements_plist_path)
157
+
158
+ entitlements_plist_dict = Xcodeproj::Plist.read_from_path(entitlements_plist_path)
159
+
160
+ if !group_id.nil? && !entitlements_plist_dict['com.apple.security.application-groups'].nil?
161
+ entitlements_plist_dict['com.apple.security.application-groups'] = [group_id]
162
+ end
163
+
164
+ if !icloud_id.nil?
165
+ entitlements_plist_dict['com.apple.developer.icloud-container-identifiers'] = [icloud_id]
166
+ entitlements_plist_dict['com.apple.developer.ubiquity-container-identifiers'] = [icloud_id]
167
+ end
168
+
169
+ Xcodeproj::Plist.write_to_path(entitlements_plist_dict, entitlements_plist_path)
170
+ end
171
+ end
172
+
173
+
174
+ def modify_info_plist_icloud(plist_file_name:nil, icloud_id:nil)
175
+ if ! File.exist? (plist_file_name)
176
+ raise Informative, "修改Info.list 路径错误!!! #{plist_file_name}"
177
+ end
178
+ if File.exist?(plist_file_name)
179
+ info_plist_dict = Xcodeproj::Plist.read_from_path(plist_file_name)
180
+
181
+ if !icloud_id.nil?
182
+
183
+ temp_value = {}
184
+ if !info_plist_dict['NSUbiquitousContainers'].nil? && info_plist_dict['NSUbiquitousContainers'].is_a?(Hash)
185
+ info_plist_dict['NSUbiquitousContainers'].each do |key, value|
186
+ if key.include?("iCloud.")
187
+ temp_value = value
188
+ break;
189
+ end
190
+ end
191
+ end
192
+ info_plist_dict['NSUbiquitousContainers'] = {}
193
+ info_plist_dict['NSUbiquitousContainers'][icloud_id] = temp_value || {}
194
+ else
195
+ info_plist_dict['NSUbiquitousContainers'] = nil
196
+ end
197
+
198
+ Xcodeproj::Plist.write_to_path(info_plist_dict, plist_file_name)
199
+
200
+ end
201
+ end
202
+
203
+ def create_upload_cert_info(apple_id:nil, cert_type:nil, provisioning_info_array:nil)
204
+
205
+ cert_dir = File.join(Dir.pwd, "cert")
206
+ cert_json_file = File.join(cert_dir, "certs.json")
207
+
208
+ if !File.exist?(cert_dir)
209
+ FileUtils.mkdir_p(cert_dir)
210
+ end
211
+
212
+ cert_json = []
213
+ begin
214
+ cert_json = JSON.parse(File.read(cert_json_file)) if File.exist?(cert_json_file)
215
+ cert_json = cert_json || []
216
+ rescue StandardError => e
217
+ cert_json = []
218
+ end
219
+
220
+ bundle_id = provisioning_info_array.select { |s| s["type"].to_s.eql?("bundle_id") }.first["bundle_id"]
221
+ team_id_vaule = provisioning_info_array.first["team_id"]
222
+ bundle_id_signing_identity = provisioning_info_array.first["signing_identity"]
223
+
224
+ account_cert_set = {}
225
+ select_result= cert_json.select { |x| x["account_name"].eql?(apple_id) }.first
226
+ if select_result.nil?
227
+
228
+ account_cert_set = {}
229
+ else
230
+
231
+ account_cert_set = select_result
232
+ cert_json.delete_if { |x| x["account_name"].eql?(apple_id) }
233
+ end
234
+
235
+ account_cert_set["account_name"] = apple_id
236
+ account_cert_set["team_id"] = team_id_vaule
237
+ account_cert_set["certs"] = account_cert_set["certs"] || []
238
+
239
+ cert_item = {}
240
+ cert_item_result = account_cert_set["certs"].select { |x| x["cert_id"].eql?(bundle_id_signing_identity)}.first
241
+ if cert_item_result.nil?
242
+ cert_item = {}
243
+ else
244
+ cert_item = cert_item_result
245
+ account_cert_set["certs"].delete_if { |x| x["cert_id"].eql?(bundle_id_signing_identity)}
246
+ end
247
+
248
+ cert_item["cert_id"] = cert_item["cert_id"] || bundle_id_signing_identity
249
+ cert_item["password"] = "goodcert1"
250
+ cert_item["cert_file"] = "#{cert_type}.p12".downcase
251
+ cert_item["cert_type"] = cert_type.downcase
252
+ cert_item["cert_provisioning_group"] = cert_item["cert_provisioning_group"] || []
253
+
254
+
255
+
256
+ cert_provisioning_group_item = {}
257
+ provisioning_group_id = [cert_type, "group", bundle_id].join("_")
258
+
259
+ provisioning_group_result = cert_item["cert_provisioning_group"].select { |x| x["provisioning_group_id"].eql?(provisioning_group_id)}.first
260
+ if provisioning_group_result.nil?
261
+ cert_provisioning_group_item = {}
262
+ else
263
+ cert_provisioning_group_item = provisioning_group_result
264
+ cert_item["cert_provisioning_group"].delete_if { |x| x["provisioning_group_id"].eql?(provisioning_group_id)}
265
+ end
266
+
267
+
268
+
269
+ cert_provisioning_group_item["provisioning_group_id"] = provisioning_group_id
270
+ cert_provisioning_group_item["provisioning_main_bundle_id"] = bundle_id
271
+ cert_provisioning_group_item["provisioning_items"] = []
272
+
273
+ group_id = [cert_type, "group", bundle_id].join("_")
274
+ provisioning_info_array.each do |provisioning_info|
275
+ bundle_id_temp = provisioning_info['bundle_id']
276
+ provisioning_id = [cert_type, bundle_id_temp].join("_")
277
+
278
+ cert_provisioning_group_item["provisioning_items"] << {
279
+ "bundle_id" => bundle_id_temp,
280
+ "provisioning_id" => provisioning_id,
281
+ "group_id" => group_id,
282
+ "provisioning_file" => provisioning_id + ".mobileprovision"
283
+ }
284
+ real_path = provisioning_info["profile_path"]
285
+ FileUtils.cp_r(real_path, File.join(cert_dir, provisioning_id + ".mobileprovision"))
286
+
287
+ end
288
+
289
+ cert_item["cert_provisioning_group"] << cert_provisioning_group_item
290
+ account_cert_set["certs"] << cert_item
291
+ cert_json << account_cert_set
292
+ File.open(cert_json_file, "w") do |f|
293
+ f.write(JSON.pretty_generate(cert_json.compact))
294
+ end
295
+
296
+ return account_cert_set
297
+ end
298
+
299
+
300
+ end
301
+ end