mmine 0.7.9 → 0.8.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39ef8e52ffb364295b176268ff21eeb2993f38f166218eea7d5b550daa47056c
4
- data.tar.gz: 69fed5318314592325f19620ae2d0713a34f2427927a12fd1e66d0405258b084
3
+ metadata.gz: a8bfb9daf037ef25eb7af299cfbcba827a2eba35045b8e244db1220e9ca61cc4
4
+ data.tar.gz: 5c3854a225f148ff1f86143249a2ecaf2ce5e1595f8f316bd58d3429281d4e17
5
5
  SHA512:
6
- metadata.gz: '05480b48aefb7347717672a7664be4eb20c8690467c5ea80ff27621fe68099a1cfd3bcb8ef4af1f1be10d6eac222792fd19e2ad1aeb536d4a62285cb5c27e156'
7
- data.tar.gz: 5818df7709198cf04de6b8bc07f166e1d30ee64599532855f48add55419e309fbb32283d6e522375f314f4e2f712dd71afaddde0a563056c6eac01429145864b
6
+ metadata.gz: 12b627f15665c97d1d4f96c305d2947e2247eecbc4e59639153916447eef47d369b41198b1955bd48d4f3f836be2a6ece4b58deeea14d3dc7b7f48c8d6aee542
7
+ data.tar.gz: ff5e7aaf7cad78c817a6fa39f54b700a83004e41c20406d419edfc8a49f646aba65c9493c64e9a33cb14f1eb2c9f808587228990879dd6acef14f7781beb3fc1
data/bin/mmine CHANGED
@@ -54,7 +54,7 @@ when "integrate"
54
54
  else
55
55
  integrator.logger.level = Logger::WARN
56
56
  end
57
- integrator.setupNotificationExtension()
57
+ integrator.setup_notification_extension
58
58
  rescue OptionParser::InvalidOption, OptionParser::MissingArgument
59
59
  puts $!.to_s
60
60
  puts integrate_parse
@@ -4,486 +4,533 @@ require 'pathname'
4
4
  require 'nokogiri'
5
5
  require 'logger'
6
6
  require 'json'
7
+ require 'set'
7
8
  require_relative 'version'
8
9
 
9
10
  module Mmine
10
- def self.root
11
- File.expand_path '../..', File.dirname(__FILE__)
12
- end
11
+ def self.root
12
+ File.expand_path '../..', File.dirname(__FILE__)
13
+ end
13
14
  end
14
15
 
15
16
  class NotificationExtensionIntegrator
16
- def initialize(application_code, project_file_path, app_group, main_target_name, cordova = false, swift_ver)
17
- @project_file_path = project_file_path
18
- @app_group = app_group
19
- @main_target_name = main_target_name
20
- @logger = nil
21
- @cordova = cordova
22
- @swift_version = swift_ver
23
- @application_code = application_code
24
-
25
- @project_dir = Pathname.new(@project_file_path).parent.to_s
26
- @project = Xcodeproj::Project.open(@project_file_path)
27
- @project_name = @project.root_object.name
28
- @ne_target_name = 'MobileMessagingNotificationExtension'
29
- @framework_file_name = "MobileMessaging.framework"
30
- @extension_source_name_filepath = File.join(Mmine.root, 'resources','NotificationService.swift')
31
- @extension_dir_name = 'NotificationExtension'
32
- @extension_destination_dir = File.join(@project_dir, @extension_dir_name)
33
- @extension_code_destination_filepath = File.join(@extension_destination_dir, 'NotificationService.swift')
34
- @extension_group_name = 'NotificationExtensionGroup'
35
-
36
- @plist_name = 'MobileMessagingNotificationServiceExtension.plist'
37
- @plist_source_filepath = File.join(Mmine.root, 'resources', @plist_name)
38
- @extension_info_plist_path = File.join(@project_dir, @extension_dir_name, @plist_name)
39
-
40
- @main_target = @project.native_targets().select { |target| target.name == @main_target_name }.first
41
- @main_target_build_settings_debug = @main_target.build_configurations.select { |config| config.type == :debug }.first.build_settings
42
- @main_target_build_settings_release = @main_target.build_configurations.select { |config| config.type == :release }.first.build_settings
43
- @main_target_debug_plist = resolveAbsolutePath(@main_target_build_settings_debug["INFOPLIST_FILE"])
44
- @main_target_release_plist = resolveAbsolutePath(@main_target_build_settings_release["INFOPLIST_FILE"])
45
- end
46
-
47
- def logger=(_logger)
48
- @logger = _logger
49
- end
50
- def logger
51
- return @logger
52
- end
53
-
54
- def setupNotificationExtension
55
- puts "🏎 Integration starting... ver. #{Mmine::VERSION}"
56
- createNotificationExtensionTarget()
57
- createNotificationExtensionDir()
58
- addNotificationExtensionSourceCode()
59
- setupDevelopmentTeam()
60
- setupDeploymentTarget()
61
- setupNotificationExtensionInfoPlist()
62
- setupNotificationExtensionBundleId()
63
-
64
- setupUserAppGroupValue()
65
- setupBackgroundModesPlistValue()
66
-
67
- setupTargetCapabilities(@ne_target.uuid)
68
- setupTargetCapabilities(@main_target.uuid)
69
-
70
- setupEmbedExtensionAction()
71
- setupMainTargetDependency()
72
- setupSwiftVersion()
73
- setupProductName()
74
- setupBuildNumber()
75
-
76
- if @cordova
77
- setupEntitlements(resolveAbsolutePath("$(PROJECT_DIR)/$(PROJECT_NAME)/Entitlements-Debug.plist"),resolveAbsolutePath("$(PROJECT_DIR)/$(PROJECT_NAME)/Entitlements-Release.plist"), nil, @main_target_build_settings_debug, @main_target_build_settings_release)
78
- setupFrameworkSearchPaths()
79
- setupRunpathSearchPaths()
80
- setupLibCordovaLink()
81
- setupCopyFrameworkScript()
82
- else
83
- setupEntitlements(@main_target_build_settings_debug['CODE_SIGN_ENTITLEMENTS'], @main_target_build_settings_release['CODE_SIGN_ENTITLEMENTS'], @main_target_name, @main_target_build_settings_debug, @main_target_build_settings_release)
84
- setupEntitlements(@extension_build_settings_debug['CODE_SIGN_ENTITLEMENTS'], @extension_build_settings_release['CODE_SIGN_ENTITLEMENTS'], @ne_target_name, @extension_build_settings_debug, @extension_build_settings_release)
85
- end
86
-
87
- @project.save()
88
- puts "🏁 Integration has been finished successfully!"
89
- end
90
-
91
- def createNotificationExtensionTarget
92
- @ne_target = @project.native_targets().select { |target| target.name == @ne_target_name }.first
93
- if @ne_target == nil
94
- @logger.info("Creating notification extension target with name #{@ne_target_name}")
95
- @ne_target = @project.new_target(:app_extension, @ne_target_name, :ios)
96
- else
97
- @logger.info("Notification extension target already exists, reusing...")
98
- end
99
-
100
- @extension_build_settings_debug = @ne_target.build_configurations.select { |config| config.name == 'Debug' }.first.build_settings
101
- @extension_build_settings_release = @ne_target.build_configurations.select { |config| config.name == 'Release' }.first.build_settings
102
-
103
- @ne_target.frameworks_build_phase.files_references.each { |ref|
104
- @ne_target.frameworks_build_phase.remove_file_reference(ref)
105
- }
106
-
107
- @logger.info("Notification extension target debug build settings:\n#{JSON.pretty_generate(@extension_build_settings_debug)}")
108
- @logger.info("Notification extension target release build settings:\n#{JSON.pretty_generate(@extension_build_settings_release)}")
109
- end
110
-
111
- def createNotificationExtensionDir
112
- unless File.directory?(@extension_destination_dir)
113
- @logger.info("Creating directory: #{@extension_destination_dir}")
114
- FileUtils.mkdir_p(@extension_destination_dir)
115
- else
116
- @logger.info("Notification extension directory already exists: #{@extension_destination_dir}")
117
- end
118
- end
119
-
120
- def addNotificationExtensionSourceCode
121
- unless File.exist?(@extension_code_destination_filepath)
122
- @logger.info("Copying notification extension source code to path: #{@extension_code_destination_filepath}")
123
- FileUtils.cp(@extension_source_name_filepath, @extension_code_destination_filepath)
124
- filereference = getNotificationExtensionGroupReference().new_reference(@extension_code_destination_filepath)
125
- @ne_target.add_file_references([filereference])
126
- else
127
- @logger.info("Notification extension source code already exists on path: #{@extension_code_destination_filepath}")
128
- end
129
- putApplicationCodeInSourceCode()
130
- end
131
-
132
- def putApplicationCodeInSourceCode
133
- source_code = File.read(@extension_code_destination_filepath)
134
- modified_source_code = source_code.gsub(/<# put your Application Code here #>/, "\"#{@application_code}\"")
135
- unless source_code == modified_source_code
136
- File.open(@extension_code_destination_filepath, "w") do |file|
137
- @logger.info("\tWriting application code to source code at #{@extension_code_destination_filepath}")
138
- file.puts modified_source_code
139
- end
140
- end
141
- end
142
-
143
- def setupDevelopmentTeam
144
- setNotificationExtensionBuildSettings('DEVELOPMENT_TEAM', @main_target_build_settings_debug['DEVELOPMENT_TEAM'], @main_target_build_settings_release['DEVELOPMENT_TEAM'])
145
- end
146
-
147
- def setupDeploymentTarget
148
- setNotificationExtensionBuildSettings('IPHONEOS_DEPLOYMENT_TARGET', "10.0")
149
- end
150
-
151
- def setupNotificationExtensionInfoPlist
152
- unless File.exist?(@extension_info_plist_path)
153
- @logger.info("Copying extension plist file to path: #{@extension_info_plist_path}")
154
- FileUtils.cp(@plist_source_filepath, @extension_info_plist_path)
155
- getNotificationExtensionGroupReference().new_reference(@extension_info_plist_path) #check if additional plist manipulations needed (target membership?)
156
- else
157
- @logger.info("Notification extension info plist already exists on path: #{@extension_info_plist_path}")
158
- end
159
- setNotificationExtensionBuildSettings('INFOPLIST_FILE', resolveXcodePath(@extension_info_plist_path))
160
- end
161
-
162
- def setupNotificationExtensionBundleId
163
- suffix = "notification-extension"
164
- debug_id = @main_target_build_settings_debug['PRODUCT_BUNDLE_IDENTIFIER']
165
- release_id = @main_target_build_settings_release['PRODUCT_BUNDLE_IDENTIFIER']
166
- if debug_id and release_id
167
- @logger.info("Composing extension bundle id from main target build settings: debug #{debug_id}, release #{release_id}")
168
- setNotificationExtensionBuildSettings('PRODUCT_BUNDLE_IDENTIFIER', "#{debug_id}.#{suffix}", "#{release_id}.#{suffix}")
169
- else
170
- key = "CFBundleIdentifier"
171
- main_bundle_id = getXMLStringValue(key, @main_target_release_plist)
172
- extension_bundle_id = "#{main_bundle_id}.#{suffix}"
173
- @logger.info("Composing extension bundle id from main target info plist: #{main_bundle_id}.")
174
- setNotificationExtensionBuildSettings('PRODUCT_BUNDLE_IDENTIFIER', extension_bundle_id)
175
- end
176
- end
177
-
178
- def createEntitlementsFile(_entitlements_name)
179
- entitlements_destination_filepath = File.join(@project_dir, _entitlements_name)
180
- entitlements_source_filepath = File.join(Mmine.root, 'resources', "MobileMessagingNotificationExtension.entitlements")
181
- unless File.exist?(entitlements_destination_filepath)
182
- @logger.info("\tCopying entitlemenst file to path: #{entitlements_destination_filepath}")
183
- FileUtils.cp(entitlements_source_filepath, entitlements_destination_filepath)
184
- ref = @project.main_group.new_reference(entitlements_destination_filepath)
185
- ref.last_known_file_type = "text.xml"
186
- else
187
- @logger.info("\tEntitlements file already exists on path: #{entitlements_destination_filepath}")
188
- end
189
- return resolveXcodePath(entitlements_destination_filepath)
190
- end
191
-
192
- def setupEntitlements(entitlements_debug_filepath, entitlements_release_filepath, target_name, _build_settings_debug, _build_settings_release)
193
- key = 'CODE_SIGN_ENTITLEMENTS'
194
-
195
- if entitlements_debug_filepath == nil and entitlements_release_filepath == nil and target_name != nil
196
- @logger.info("\tEntitlements are not set for both release and debug schemes, setting up...")
197
- entitlements_destination_filepath = createEntitlementsFile("#{target_name}.entitlements")
198
-
199
- @logger.info("\tSetting build settings:\n\t\tdebug: \t#{key}\t#{entitlements_destination_filepath}\n\t\trelease:\t#{key}\t#{entitlements_destination_filepath}")
200
-
201
- _build_settings_debug[key] = entitlements_destination_filepath
202
- _build_settings_release[key] = entitlements_destination_filepath
203
- entitlements_debug_filepath = entitlements_destination_filepath
204
- entitlements_release_filepath = entitlements_destination_filepath
205
- end
206
-
207
- if entitlements_debug_filepath == entitlements_release_filepath
208
- @logger.info("\tEntitlements settings are equal for debug and release schemes.")
209
-
210
- putKeyArrayElement("com.apple.security.application-groups", @app_group, entitlements_debug_filepath)
211
- putStringValueIntoXML("aps-environment", "development", entitlements_debug_filepath)
212
- else
213
- if entitlements_debug_filepath == nil and target_name != nil
214
- @logger.error("\tEntitlements debug settings are not set, creating entitlements file")
215
- entitlements_debug_filepath = createEntitlementsFile("#{target_name}_debug.entitlements")
216
- _build_settings_debug[key] = entitlements_debug_filepath
217
- end
218
-
219
- if entitlements_release_filepath == nil and target_name != nil
220
- @logger.error("\tEntitlements release settings are not set, creating entitlements file")
221
- entitlements_release_filepath = createEntitlementsFile("#{target_name}_release.entitlements")
222
- _build_settings_release[key] = entitlements_release_filepath
223
- end
224
-
225
- putKeyArrayElement("com.apple.security.application-groups", @app_group, entitlements_debug_filepath)
226
- putStringValueIntoXML("aps-environment", "development", entitlements_debug_filepath)
227
- putKeyArrayElement("com.apple.security.application-groups", @app_group, entitlements_release_filepath)
228
- putStringValueIntoXML("aps-environment", "production", entitlements_release_filepath)
229
- end
230
- end
231
-
232
- def setupUserAppGroupValue
233
- putStringValueIntoXML("com.mobilemessaging.app_group", @app_group, @main_target_debug_plist)
234
- putStringValueIntoXML("com.mobilemessaging.app_group", @app_group, @main_target_release_plist)
235
- end
236
-
237
- def setupBackgroundModesPlistValue
238
- putKeyArrayElement("UIBackgroundModes", "remote-notification", @main_target_debug_plist)
239
- putKeyArrayElement("UIBackgroundModes", "remote-notification", @main_target_release_plist)
240
- end
241
-
242
- def setupEmbedExtensionAction
243
- phase_name = 'Embed App Extensions'
244
- unless @main_target.copy_files_build_phases.select { |phase| phase.name == phase_name }.first
245
- @logger.info("Adding copy files build phase: #{phase_name}")
246
- new_phase = @main_target.new_copy_files_build_phase(phase_name)
247
- new_phase.dst_subfolder_spec = '13'
248
- new_phase.add_file_reference(@ne_target.product_reference)
249
- end
250
- end
251
-
252
- def setupMainTargetDependency
253
- unless @main_target.dependency_for_target(@ne_target)
254
- @logger.info("Adding extension target dependency for main target")
255
- @main_target.add_dependency(@ne_target)
256
- end
257
- end
258
-
259
- def setupFrameworkSearchPaths
260
- setNotificationExtensionBuildSettings('FRAMEWORK_SEARCH_PATHS', '$SRCROOT/$PROJECT/Plugins/com-infobip-plugins-mobilemessaging')
261
- end
262
-
263
- def setupRunpathSearchPaths
264
- setNotificationExtensionBuildSettings('LD_RUNPATH_SEARCH_PATHS', '@executable_path/../../Frameworks')
265
- end
266
-
267
- def setupSwiftVersion
268
- setNotificationExtensionBuildSettings('SWIFT_VERSION', @swift_version)
269
- end
270
-
271
- def setupProductName
272
- setNotificationExtensionBuildSettings('PRODUCT_NAME', @ne_target_name)
273
- end
274
-
275
- def setupBuildNumber
276
- version_key = "CFBundleShortVersionString"
277
- build_key = "CFBundleVersion"
278
- main_version = getXMLStringValue(version_key, @main_target_release_plist)
279
- main_build = getXMLStringValue(build_key, @main_target_release_plist)
280
- putStringValueIntoXML(version_key, main_version, @extension_info_plist_path)
281
- putStringValueIntoXML(build_key, main_build, @extension_info_plist_path)
282
- end
283
-
284
- def setupLibCordovaLink
285
- lib_cordova_name = 'libCordova.a'
286
- unless @ne_target.frameworks_build_phase.files_references.select { |ref| ref.path == lib_cordova_name }.first
287
- @logger.info("Adding libCordova.a to Notification Extension target...")
288
- ref = @main_target.frameworks_build_phase.files_references.select { |ref| ref.path == lib_cordova_name }.first
289
- if ref
290
- @ne_target.frameworks_build_phase.add_file_reference(ref)
291
- else
292
- @logger.error("Main target has no libCordova.a as a linked library. Unable to add libCordova.a to Notification Extension target!")
293
- end
294
- else
295
- @logger.info("Notification Extension target already has libCordova.a linked.")
296
- end
297
- end
298
-
299
- def setupCopyFrameworkScript
300
- phase_name = "Copy Frameworks"
301
- shell_script = "/usr/local/bin/carthage copy-frameworks"
302
- input_path = "$SRCROOT/$PROJECT/Plugins/com-infobip-plugins-mobilemessaging/#{@framework_file_name}"
303
- output_path = "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/#{@framework_file_name}"
304
- existing_phase = @main_target.shell_script_build_phases.select { |phase| phase.shell_script.include? shell_script }.first
305
-
306
- unless existing_phase
307
- @logger.info("Setting up #{phase_name} shell script for main target")
308
- new_phase = @main_target.new_shell_script_build_phase(phase_name)
309
- new_phase.shell_path = "/bin/sh"
310
- new_phase.shell_script = shell_script
311
- new_phase.input_paths << input_path
312
- new_phase.output_paths << output_path
313
- else
314
- existing_phase.input_paths |= [input_path]
315
- existing_phase.output_paths |= [output_path]
316
-
317
- @logger.info("Main target already has #{phase_name} shell script set up")
318
- end
319
- removeEmbedFrameworkPhase()
320
- end
321
-
322
- def setupTargetCapabilities(target_uuid)
323
- unless @project.root_object.attributes["TargetAttributes"]
324
- @project.root_object.attributes["TargetAttributes"] = Hash.new
325
- end
326
- exitsting_capabilities = @project.root_object.attributes["TargetAttributes"][target_uuid]
327
- mobilemessaging_capabilities = { "SystemCapabilities" =>
328
- {
329
- "com.apple.ApplicationGroups.iOS" => { "enabled" => 1 },
330
- "com.apple.Push" => { "enabled" => 1 },
331
- "com.apple.BackgroundModes" => { "enabled" => 1 }
332
- }
333
- }
334
- if exitsting_capabilities == nil
335
- @logger.info("\tSetting TargetAttributes #{mobilemessaging_capabilities} for target #{target_uuid}")
336
- @project.root_object.attributes["TargetAttributes"][target_uuid] = mobilemessaging_capabilities
337
- else
338
- @logger.info("\tMerging TargetAttributes #{mobilemessaging_capabilities} for target #{target_uuid}")
339
- @project.root_object.attributes["TargetAttributes"][target_uuid] = exitsting_capabilities.merge(mobilemessaging_capabilities)
340
- end
341
- end
342
-
343
- def removeEmbedFrameworkPhase
344
- @logger.info("Setting up embed framework script")
345
- emb_fs = @main_target.copy_files_build_phases
346
- .select { |phase|
347
- phase.dst_subfolder_spec == '10'
348
- }.each { |phase|
349
- phase.files.select { |file|
350
- file.display_name == @framework_file_name
351
- }.each { |file|
352
- @logger.info("\tRemoving embeddin #{@framework_file_name} from phase #{phase.display_name}")
353
- phase.remove_build_file(file)
354
- }
355
- }
356
- end
357
-
358
- def resolveXcodePath(path)
359
- return path.sub(@project_dir, '$(PROJECT_DIR)')
360
- end
361
-
362
- def setNotificationExtensionBuildSettings(key, debug_value, release_value=nil)
363
- release_value = release_value != nil ? release_value : debug_value
364
- @logger.info("\tSetting extension build settings:\n\t\tdebug: \t#{key}\t#{debug_value}\n\t\trelease:\t#{key}\t#{release_value}")
365
- @extension_build_settings_debug[key] = debug_value
366
- @extension_build_settings_release[key] = release_value
367
- end
368
-
369
- def getNotificationExtensionGroupReference
370
- group_reference = @project.groups().select { |group| group.name == @extension_group_name }.first
371
- if group_reference == nil
372
- group_reference = @project.new_group(@extension_group_name, @extension_destination_dir)
373
- end
374
- return group_reference
375
- end
376
-
377
- def resolveAbsolutePath(path)
378
- ret = path
379
- ["$(PROJECT_DIR)", "$PROJECT_DIR"].each do |proj_dir|
380
- ret = ret.sub(proj_dir, @project_dir)
381
- end
382
-
383
- ["$(PROJECT_NAME)", "$PROJECT_NAME"].each do |proj_name|
384
- ret = ret.sub(proj_name, @project_name)
385
- end
386
-
387
- if ret.include?("$")
388
- puts "Could not resolve absolute path for #{path}. Make sure you don't misuse Xcode paths variables, contact Infobip Mobile Messaging support via email Push.Support@infobip.com"
389
- exit
390
- end
391
-
392
- if ret == path && !ret.include?("$") # no aliases found/replaced, no aliases left in path
393
- if path.start_with? "/"
394
- return path # it's already an absolute path
395
- else
396
- return File.join(@project_dir, path) # it's a relative project path
397
- end
398
- end
399
- return ret
400
- end
401
-
402
- def getXMLStringValue(key, plist_path)
403
- plist_path = resolveAbsolutePath(plist_path)
404
- doc = Nokogiri::XML(IO.read(plist_path))
405
- key_node = doc.search("//dict//key[text() = '#{key}']").first
406
- if key_node == nil
407
- return nil
408
- else
409
- existing_string_value_node = key_node.xpath("following-sibling::*").first
410
- if existing_string_value_node.name == 'string'
411
- return existing_string_value_node.content
412
- else
413
- return nil
414
- end
415
- end
416
- end
417
-
418
- def putStringValueIntoXML(key, value, plist_path)
419
- plist_path = resolveAbsolutePath(plist_path)
420
- @logger.info("\tConfiguring plist on path: #{plist_path}")
421
- doc = Nokogiri::XML(IO.read(plist_path))
422
- key_node = doc.search("//dict//key[text() = '#{key}']").first
423
- string_value_node = Nokogiri::XML::Node.new("string",doc)
424
- string_value_node.content = value
425
- if key_node == nil
426
- @logger.info("\tAdding 'key' node with content #{key}")
427
- key_node = Nokogiri::XML::Node.new("key",doc)
428
- key_node.content = key
429
- doc.xpath("//dict").first.add_child(key_node)
430
- @logger.info("\tAdding next string sibling with content #{string_value_node}")
431
- key_node.add_next_sibling(string_value_node)
432
- else
433
- @logger.info("\t'Key' node with content #{key} already extists.")
434
- existing_string_value_node = key_node.xpath("following-sibling::*").first
435
- if existing_string_value_node.name == 'string'
436
- @logger.info("\tUpdating following string sibling value with #{value}")
437
- existing_string_value_node.content = value
438
- else
439
- @logger.info("\tAdding next string sibling with content #{string_value_node}")
440
- key_node.add_next_sibling(string_value_node)
441
- end
442
- end
443
-
444
- File.open(plist_path,'w') do |file|
445
- @logger.info("\tWriting changes to plist: #{plist_path}")
446
- file.puts Nokogiri::XML(doc.to_xml) { |x| x.noblanks }
447
- end
448
- end
449
-
450
- def putKeyArrayElement(key, value, filepath) # check if it appends to existing array
451
- filepath = resolveAbsolutePath(filepath)
452
- doc = Nokogiri::XML(IO.read(filepath))
453
- key_node = doc.search("//dict//key[text() = '#{key}']").first
454
- string_app_group_value = Nokogiri::XML::Node.new("string",doc)
455
- string_app_group_value.content = value
456
- if key_node == nil
457
- @logger.info("\tAdding 'key' node with content #{key}")
458
- key_node = Nokogiri::XML::Node.new("key",doc)
459
- key_node.content = key
460
- array_node = Nokogiri::XML::Node.new("array",doc)
461
- array_node.add_child(string_app_group_value)
462
-
463
- doc.xpath("//dict").first.add_child(key_node)
464
- key_node.add_next_sibling(array_node)
465
- else
466
- @logger.info("\t'Key' node with content #{key} already extists.")
467
- array_node = key_node.xpath("following-sibling::*").first
468
- if array_node.name == 'array'
469
- @logger.info("\tFollowing array sibling already exists")
470
- unless array_node.xpath("//string[text() = '#{value}']").first
471
- @logger.info("\tAdding child string element with content #{value}")
472
- array_node.add_child(string_app_group_value)
473
- else
474
- @logger.info("\tArray string element with content #{value} already exists")
475
- end
476
- else
477
- @logger.info("\tFollowing array sibling is missing. Adding array node containing a string element.")
478
- array_node = Nokogiri::XML::Node.new("array",doc)
479
- array_node.add_child(string_app_group_value)
480
- key_node.add_next_sibling(array_node)
481
- end
482
- end
483
-
484
- File.open(filepath,'w') do |file|
485
- @logger.info("\tWriting changes to entitlements: #{filepath}")
486
- file.puts Nokogiri::XML(doc.to_xml) { |x| x.noblanks }
487
- end
488
- end
17
+ def initialize(application_code, project_file_path, app_group, main_target_name, cordova = false, swift_ver)
18
+ @project_file_path = project_file_path
19
+ @app_group = app_group
20
+ @main_target_name = main_target_name
21
+ @logger = nil
22
+ @cordova = cordova
23
+ @swift_version = swift_ver
24
+ @application_code = application_code
25
+
26
+ @project_dir = Pathname.new(@project_file_path).parent.to_s
27
+ @project = Xcodeproj::Project.open(@project_file_path)
28
+ @project_name = @project.root_object.name
29
+ @framework_file_name = "MobileMessaging.framework"
30
+
31
+ @main_target = @project.native_targets.select { |target| target.name == @main_target_name }.first
32
+ @main_build_configurations_debug = @main_target.build_configurations.select { |config| config.type == :debug }
33
+ @main_build_configurations_release = @main_target.build_configurations.select { |config| config.type == :release }
34
+ @main_build_settings_debug = @main_build_configurations_debug.map(&:build_settings)
35
+ @main_build_settings_release = @main_build_configurations_release.map(&:build_settings)
36
+ end
37
+
38
+ def logger=(_logger)
39
+ @logger = _logger
40
+ end
41
+
42
+ def logger
43
+ @logger
44
+ end
45
+
46
+ def setup_notification_extension
47
+ puts "🏎 Integration starting... ver. #{Mmine::VERSION}"
48
+ @logger.debug("\n@main_target_build_configurations_debug #{@main_build_configurations_debug}\n@main_target_build_configurations_release #{@main_build_configurations_release}")
49
+ create_notification_extension_target
50
+ create_notification_extension_dir
51
+ add_notification_extension_source_code
52
+ setup_development_team
53
+ setup_deployment_target
54
+ setup_notification_extension_info_plist
55
+ setup_notification_extension_bundle_id
56
+
57
+ setup_user_app_group_value
58
+ setup_background_modes_plist_value
59
+
60
+ setup_target_capabilities(@extension_target.uuid)
61
+ setup_target_capabilities(@main_target.uuid)
62
+
63
+ setup_embed_extension_action
64
+ setup_main_target_dependency
65
+ setup_swift_version
66
+ setup_product_name
67
+ setup_extension_build_number
68
+
69
+ if @cordova
70
+ setup_entitlements(resolve_absolute_paths(["$(PROJECT_DIR)/$(PROJECT_NAME)/Entitlements-Debug.plist"]),
71
+ resolve_absolute_paths(["$(PROJECT_DIR)/$(PROJECT_NAME)/Entitlements-Release.plist"]),
72
+ nil,
73
+ @main_build_settings_debug,
74
+ @main_build_settings_release)
75
+ setup_framework_search_paths
76
+ setup_run_path_search_paths
77
+ setup_extension_lib_cordova_link
78
+ setup_copy_framework_script
79
+ else
80
+ setup_entitlements(@main_build_configurations_debug.map { |config| config.resolve_build_setting('CODE_SIGN_ENTITLEMENTS') },
81
+ @main_build_configurations_release.map { |config| config.resolve_build_setting('CODE_SIGN_ENTITLEMENTS') },
82
+ @main_target_name,
83
+ @main_build_settings_debug,
84
+ @main_build_settings_release)
85
+
86
+ setup_entitlements(@extension_build_configurations_debug.map { |config| config.resolve_build_setting('CODE_SIGN_ENTITLEMENTS') },
87
+ @extension_build_configurations_release.map { |config| config.resolve_build_setting('CODE_SIGN_ENTITLEMENTS') },
88
+ @extension_target_name,
89
+ @extension_build_settings_debug,
90
+ @extension_build_settings_release)
91
+ end
92
+
93
+ @project.save
94
+ puts "🏁 Integration has been finished successfully!"
95
+ end
96
+
97
+ def create_notification_extension_target
98
+ @extension_target_name = 'MobileMessagingNotificationExtension'
99
+ @extension_source_name_filepath = File.join(Mmine.root, 'resources', 'NotificationService.swift')
100
+ @extension_dir_name = 'NotificationExtension'
101
+ @extension_destination_dir = File.join(@project_dir, @extension_dir_name)
102
+ @extension_code_destination_filepath = File.join(@extension_destination_dir, 'NotificationService.swift')
103
+ @extension_group_name = 'NotificationExtensionGroup'
104
+ @extension_plist_name = 'MobileMessagingNotificationServiceExtension.plist'
105
+ @extension_plist_source_filepath = File.join(Mmine.root, 'resources', @extension_plist_name)
106
+ @extension_info_plist_path = File.join(@project_dir, @extension_dir_name, @extension_plist_name)
107
+ @extension_target = @project.native_targets.select { |target| target.name == @extension_target_name }.first
108
+ if @extension_target == nil
109
+ @logger.info("Creating notification extension target with name #{@extension_target_name}")
110
+ @extension_target = @project.new_target(:app_extension, @extension_target_name, :ios)
111
+ else
112
+ @logger.info("Notification extension target already exists, reusing...")
113
+ end
114
+
115
+ @extension_build_configurations_debug = @extension_target.build_configurations.select { |config| config.type == :debug }
116
+ @extension_build_configurations_release = @extension_target.build_configurations.select { |config| config.type == :release }
117
+ @extension_build_settings_debug = @extension_build_configurations_debug.map(&:build_settings)
118
+ @extension_build_settings_release = @extension_build_configurations_release.map(&:build_settings)
119
+
120
+ @extension_target.frameworks_build_phase.files_references.each { |ref|
121
+ @extension_target.frameworks_build_phase.remove_file_reference(ref)
122
+ }
123
+
124
+ @logger.info("Notification extension target debug build settings:\n#{JSON.pretty_generate(@extension_build_settings_debug)}")
125
+ @logger.info("Notification extension target release build settings:\n#{JSON.pretty_generate(@extension_build_settings_release)}")
126
+ end
127
+
128
+ def create_notification_extension_dir
129
+ if File.directory?(@extension_destination_dir)
130
+ @logger.info("Notification extension directory already exists: #{@extension_destination_dir}")
131
+ else
132
+ @logger.info("Creating directory: #{@extension_destination_dir}")
133
+ FileUtils.mkdir_p(@extension_destination_dir)
134
+ end
135
+ end
136
+
137
+ def add_notification_extension_source_code
138
+ if File.exist?(@extension_code_destination_filepath)
139
+ @logger.info("Notification extension source code already exists on path: #{@extension_code_destination_filepath}")
140
+ else
141
+ @logger.info("Copying notification extension source code to path: #{@extension_code_destination_filepath}")
142
+ FileUtils.cp(@extension_source_name_filepath, @extension_code_destination_filepath)
143
+ filereference = get_notification_extension_group_reference.new_reference(@extension_code_destination_filepath)
144
+ @extension_target.add_file_references([filereference])
145
+ end
146
+ put_application_code_in_source_code
147
+ end
148
+
149
+ def put_application_code_in_source_code
150
+ source_code = File.read(@extension_code_destination_filepath)
151
+ modified_source_code = source_code.gsub(/<# put your Application Code here #>/, "\"#{@application_code}\"")
152
+ unless source_code == modified_source_code
153
+ File.open(@extension_code_destination_filepath, "w") do |file|
154
+ @logger.info("\tWriting application code to source code at #{@extension_code_destination_filepath}")
155
+ file.puts modified_source_code
156
+ end
157
+ end
158
+ end
159
+
160
+ def setup_development_team
161
+ align_notification_extension_build_settings('DEVELOPMENT_TEAM',
162
+ @main_target.build_configurations)
163
+ end
164
+
165
+ def setup_deployment_target
166
+ set_notification_extension_build_settings('IPHONEOS_DEPLOYMENT_TARGET', "10.0")
167
+ end
168
+
169
+ def setup_notification_extension_info_plist
170
+ if File.exist?(@extension_info_plist_path)
171
+ @logger.info("Notification extension info plist already exists on path: #{@extension_info_plist_path}")
172
+ else
173
+ @logger.info("Copying extension plist file to path: #{@extension_info_plist_path}")
174
+ FileUtils.cp(@extension_plist_source_filepath, @extension_info_plist_path)
175
+ get_notification_extension_group_reference.new_reference(@extension_info_plist_path) #check if additional plist manipulations needed (target membership?)
176
+ end
177
+ set_notification_extension_build_settings('INFOPLIST_FILE', resolve_xcode_path(@extension_info_plist_path))
178
+ end
179
+
180
+ def setup_notification_extension_bundle_id #todo test it
181
+ suffix = 'notification-extension'
182
+ key = 'PRODUCT_BUNDLE_IDENTIFIER'
183
+ (@main_build_configurations_release + @main_build_configurations_debug).each do |config|
184
+ bundleId = config.resolve_build_setting(key)
185
+ if bundleId == nil
186
+ plist_path = resolve_absolute_paths(config.resolve_build_setting("INFOPLIST_FILE")).first
187
+ bundleId = get_xml_string_value(key, plist_path)
188
+ @logger.info("Composing #{key} from main target info plist: #{bundleId}.")
189
+ else
190
+ @logger.info("Composing #{key} from main target config build setting: #{bundleId}.")
191
+ end
192
+ value = "#{bundleId}.#{suffix}"
193
+ @logger.info("\tSetting extension build settings:\n\t\t#{config.name}: \t#{key}\t#{value}")
194
+ @extension_target.build_configuration_list[config.name].build_settings[key] = value
195
+ end
196
+ end
197
+
198
+ def create_entitlements_file(_entitlements_name)
199
+ entitlements_destination_filepath = File.join(@project_dir, _entitlements_name)
200
+ entitlements_source_filepath = File.join(Mmine.root, 'resources', "MobileMessagingNotificationExtension.entitlements")
201
+ if File.exist?(entitlements_destination_filepath)
202
+ @logger.info("\tEntitlements file already exists on path: #{entitlements_destination_filepath}")
203
+ else
204
+ @logger.info("\tCopying entitlements file to path: #{entitlements_destination_filepath}")
205
+ FileUtils.cp(entitlements_source_filepath, entitlements_destination_filepath)
206
+ ref = @project.main_group.new_reference(entitlements_destination_filepath)
207
+ ref.last_known_file_type = "text.xml"
208
+ end
209
+ return resolve_xcode_path(entitlements_destination_filepath)
210
+ end
211
+
212
+ def setup_entitlements(entitlements_debug_file_paths, entitlements_release_file_paths, target_name, _build_settings_debug, _build_settings_release)
213
+ entitlements_debug_file_paths = entitlements_debug_file_paths.compact
214
+ entitlements_release_file_paths = entitlements_release_file_paths.compact
215
+ @logger.debug("setup_entitlements #{entitlements_debug_file_paths} #{entitlements_release_file_paths} #{target_name} #{_build_settings_debug} #{_build_settings_release}")
216
+ code_sign_entitlements_key = 'CODE_SIGN_ENTITLEMENTS'
217
+ aps_env_key = 'aps-environment'
218
+ development = 'development'
219
+ production = 'production'
220
+ if (entitlements_debug_file_paths == nil or entitlements_debug_file_paths.empty?) and (entitlements_release_file_paths == nil or entitlements_release_file_paths.empty?) and target_name != nil
221
+ @logger.info("\tEntitlements are not set for both release and debug schemes, setting up...")
222
+ entitlements_destination_filepath = create_entitlements_file("#{target_name}.entitlements")
223
+
224
+ @logger.info("\tSetting build settings:\n\t\tdebug: \t#{code_sign_entitlements_key}\t#{entitlements_destination_filepath}\n\t\trelease:\t#{code_sign_entitlements_key}\t#{entitlements_destination_filepath}")
225
+
226
+ _build_settings_debug.each do |setting|
227
+ setting[code_sign_entitlements_key] = entitlements_destination_filepath
228
+ end
229
+ _build_settings_release.each do |setting|
230
+ setting[code_sign_entitlements_key] = entitlements_destination_filepath
231
+ end
232
+ entitlements_debug_file_paths = [entitlements_destination_filepath]
233
+ entitlements_release_file_paths = [entitlements_destination_filepath]
234
+ end
235
+
236
+ if entitlements_debug_file_paths.to_set == entitlements_release_file_paths.to_set
237
+ @logger.info("\tEntitlements settings are equal for debug and release schemes.")
238
+
239
+ put_key_array_element("com.apple.security.application-groups", @app_group, entitlements_debug_file_paths)
240
+ put_string_value_into_xml(aps_env_key, development, entitlements_debug_file_paths)
241
+ else
242
+ if (entitlements_debug_file_paths == nil or entitlements_debug_file_paths.empty?) and target_name != nil
243
+ @logger.error("\tEntitlements debug settings are not set, creating entitlements file")
244
+ entitlements_destination_filepath = create_entitlements_file("#{target_name}_debug.entitlements")
245
+ _build_settings_debug.each do |setting|
246
+ setting[code_sign_entitlements_key] = entitlements_destination_filepath
247
+ end
248
+ entitlements_debug_file_paths = [entitlements_destination_filepath]
249
+ end
250
+
251
+ if (entitlements_release_file_paths == nil or entitlements_release_file_paths.empty?) and target_name != nil
252
+ @logger.error("\tEntitlements release settings are not set, creating entitlements file")
253
+ entitlements_destination_filepath = create_entitlements_file("#{target_name}_release.entitlements")
254
+ _build_settings_release.each do |setting|
255
+ setting[code_sign_entitlements_key] = entitlements_destination_filepath
256
+ end
257
+ entitlements_release_file_paths = [entitlements_destination_filepath]
258
+ end
259
+
260
+ put_key_array_element("com.apple.security.application-groups", @app_group, entitlements_debug_file_paths + entitlements_release_file_paths)
261
+ put_string_value_into_xml(aps_env_key, development, entitlements_debug_file_paths)
262
+ put_string_value_into_xml(aps_env_key, production, entitlements_release_file_paths)
263
+ end
264
+ end
265
+
266
+ def setup_user_app_group_value
267
+ plist_paths = (@main_build_configurations_debug + @main_build_configurations_release).map { |config| config.resolve_build_setting("INFOPLIST_FILE") }
268
+ put_string_value_into_xml("com.mobilemessaging.app_group", @app_group, resolve_absolute_paths(plist_paths))
269
+ end
270
+
271
+ def setup_background_modes_plist_value
272
+ plist_paths = (@main_build_configurations_debug + @main_build_configurations_release).map { |config| config.resolve_build_setting("INFOPLIST_FILE") }
273
+ put_key_array_element("UIBackgroundModes", "remote-notification", resolve_absolute_paths(plist_paths))
274
+ end
275
+
276
+ def setup_embed_extension_action
277
+ phase_name = 'Embed App Extensions'
278
+ unless @main_target.copy_files_build_phases.select { |phase| phase.name == phase_name }.first
279
+ @logger.info("Adding copy files build phase: #{phase_name}")
280
+ new_phase = @main_target.new_copy_files_build_phase(phase_name)
281
+ new_phase.dst_subfolder_spec = '13'
282
+ new_phase.add_file_reference(@extension_target.product_reference)
283
+ end
284
+ end
285
+
286
+ def setup_main_target_dependency
287
+ unless @main_target.dependency_for_target(@extension_target)
288
+ @logger.info("Adding extension target dependency for main target")
289
+ @main_target.add_dependency(@extension_target)
290
+ end
291
+ end
292
+
293
+ def setup_framework_search_paths
294
+ set_notification_extension_build_settings('FRAMEWORK_SEARCH_PATHS', '$SRCROOT/$PROJECT/Plugins/com-infobip-plugins-mobilemessaging')
295
+ end
296
+
297
+ def setup_run_path_search_paths
298
+ set_notification_extension_build_settings('LD_RUNPATH_SEARCH_PATHS', '@executable_path/../../Frameworks')
299
+ end
300
+
301
+ def setup_swift_version
302
+ set_notification_extension_build_settings('SWIFT_VERSION', @swift_version)
303
+ end
304
+
305
+ def setup_product_name
306
+ set_notification_extension_build_settings('PRODUCT_NAME', @extension_target_name)
307
+ end
308
+
309
+ def setup_extension_build_number
310
+ version_key = "CFBundleShortVersionString"
311
+ build_key = "CFBundleVersion"
312
+ put_string_value_into_xml(version_key, '1.0', [@extension_info_plist_path])
313
+ put_string_value_into_xml(build_key, '1', [@extension_info_plist_path])
314
+ end
315
+
316
+ def setup_extension_lib_cordova_link
317
+ lib_cordova_name = 'libCordova.a'
318
+ if @extension_target.frameworks_build_phase.files_references.select { |ref| ref.path == lib_cordova_name }.first
319
+ @logger.info("Notification Extension target already has libCordova.a linked.")
320
+ else
321
+ @logger.info("Adding libCordova.a to Notification Extension target...")
322
+ ref = @main_target.frameworks_build_phase.files_references.select { |ref| ref.path == lib_cordova_name }.first
323
+ if ref
324
+ @extension_target.frameworks_build_phase.add_file_reference(ref)
325
+ else
326
+ @logger.error("Main target has no libCordova.a as a linked library. Unable to add libCordova.a to Notification Extension target!")
327
+ end
328
+ end
329
+ end
330
+
331
+ def setup_copy_framework_script
332
+ phase_name = "Copy Frameworks"
333
+ shell_script = "/usr/local/bin/carthage copy-frameworks"
334
+ input_path = "$SRCROOT/$PROJECT/Plugins/com-infobip-plugins-mobilemessaging/#{@framework_file_name}"
335
+ output_path = "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/#{@framework_file_name}"
336
+ existing_phase = @main_target.shell_script_build_phases.select { |phase| phase.shell_script.include? shell_script }.first
337
+
338
+ if existing_phase
339
+ existing_phase.input_paths |= [input_path]
340
+ existing_phase.output_paths |= [output_path]
341
+ @logger.info("Main target already has #{phase_name} shell script set up")
342
+ else
343
+ @logger.info("Setting up #{phase_name} shell script for main target")
344
+ new_phase = @main_target.new_shell_script_build_phase(phase_name)
345
+ new_phase.shell_path = "/bin/sh"
346
+ new_phase.shell_script = shell_script
347
+ new_phase.input_paths << input_path
348
+ new_phase.output_paths << output_path
349
+ end
350
+
351
+ remove_embed_framework_phase
352
+ end
353
+
354
+ def setup_target_capabilities(target_uuid)
355
+ unless @project.root_object.attributes["TargetAttributes"]
356
+ @project.root_object.attributes["TargetAttributes"] = Hash.new
357
+ end
358
+ existing_capabilities = @project.root_object.attributes["TargetAttributes"][target_uuid]
359
+ mobile_messaging_capabilities = {"SystemCapabilities" =>
360
+ {
361
+ "com.apple.ApplicationGroups.iOS" => {"enabled" => 1},
362
+ "com.apple.Push" => {"enabled" => 1},
363
+ "com.apple.BackgroundModes" => {"enabled" => 1}
364
+ }
365
+ }
366
+ if existing_capabilities == nil
367
+ @logger.info("\tSetting TargetAttributes #{mobile_messaging_capabilities} for target #{target_uuid}")
368
+ @project.root_object.attributes["TargetAttributes"][target_uuid] = mobile_messaging_capabilities
369
+ else
370
+ @logger.info("\tMerging TargetAttributes #{mobile_messaging_capabilities} for target #{target_uuid}")
371
+ @project.root_object.attributes["TargetAttributes"][target_uuid] = existing_capabilities.merge(mobile_messaging_capabilities)
372
+ end
373
+ end
374
+
375
+ def remove_embed_framework_phase
376
+ @logger.info("Setting up embed framework script")
377
+ @main_target.copy_files_build_phases
378
+ .select { |phase|
379
+ phase.dst_subfolder_spec == '10'
380
+ }
381
+ .each { |phase|
382
+ phase.files.select { |file|
383
+ file.display_name == @framework_file_name
384
+ }.each { |file|
385
+ @logger.info("\tRemoving embeddin #{@framework_file_name} from phase #{phase.display_name}")
386
+ phase.remove_build_file(file)
387
+ }
388
+ }
389
+ end
390
+
391
+ def resolve_xcode_path(path)
392
+ return path.sub(@project_dir, '$(PROJECT_DIR)')
393
+ end
394
+
395
+ def set_notification_extension_build_settings(key, value)
396
+ @logger.info("\tSetting extension build settings across all configurations :\n\t\t#{key}\t#{value}")
397
+ @extension_target.build_configuration_list.set_setting(key, value)
398
+ end
399
+
400
+ def align_notification_extension_build_settings(key, main_configurations)
401
+ main_configurations.each do |config|
402
+ value = config.resolve_build_setting(key)
403
+ @logger.info("\tSetting extension build settings:\n\t\t#{config.name}: \t#{key}\t#{value}")
404
+ @extension_target.build_configuration_list[config.name].build_settings[key] = value
405
+ end
406
+ end
407
+
408
+ def get_notification_extension_group_reference
409
+ group_reference = @project.groups.select { |group| group.name == @extension_group_name }.first
410
+ if group_reference == nil
411
+ group_reference = @project.new_group(@extension_group_name, @extension_destination_dir)
412
+ end
413
+ return group_reference
414
+ end
415
+
416
+ def resolve_absolute_paths(paths)
417
+ paths.map do |path|
418
+ ret = path
419
+ ["$(PROJECT_DIR)", "$PROJECT_DIR"].each do |proj_dir|
420
+ ret = ret.sub(proj_dir, @project_dir)
421
+ end
422
+
423
+ ["$(PROJECT_NAME)", "$PROJECT_NAME"].each do |proj_name|
424
+ ret = ret.sub(proj_name, @project_name)
425
+ end
426
+
427
+ if ret.include?("$")
428
+ puts "Could not resolve absolute path for #{path}. Make sure you don't misuse Xcode paths variables, contact Infobip Mobile Messaging support via email Push.Support@infobip.com"
429
+ exit
430
+ end
431
+
432
+ if ret == path && !ret.include?("$") # no aliases found/replaced, no aliases left in path
433
+ if path.start_with? "/"
434
+ ret = path # it's already an absolute path
435
+ else
436
+ ret = File.join(@project_dir, path) # it's a relative project path
437
+ end
438
+ end
439
+
440
+ ret
441
+ end
442
+ end
443
+
444
+ def get_xml_string_value(key, plist_path)
445
+ plist_path = resolve_absolute_paths([plist_path]).first
446
+ doc = Nokogiri::XML(IO.read(plist_path))
447
+ key_node = doc.search("//dict//key[text() = '#{key}']").first
448
+ if key_node == nil
449
+ return nil
450
+ else
451
+ existing_string_value_node = key_node.xpath("following-sibling::*").first
452
+ if existing_string_value_node.name == 'string'
453
+ return existing_string_value_node.content
454
+ else
455
+ return nil
456
+ end
457
+ end
458
+ end
459
+
460
+ def put_string_value_into_xml(key, value, plist_paths)
461
+ plist_paths.each do |plist_path|
462
+ plist_path = resolve_absolute_paths([plist_path]).first
463
+ @logger.info("\tConfiguring plist on path: #{plist_path}")
464
+ doc = Nokogiri::XML(IO.read(plist_path))
465
+ key_node = doc.search("//dict//key[text() = '#{key}']").first
466
+ string_value_node = Nokogiri::XML::Node.new("string", doc)
467
+ string_value_node.content = value
468
+ if key_node == nil
469
+ @logger.info("\tAdding 'key' node with content #{key}")
470
+ key_node = Nokogiri::XML::Node.new("key", doc)
471
+ key_node.content = key
472
+ doc.xpath("//dict").first.add_child(key_node)
473
+ @logger.info("\tAdding next string sibling with content #{string_value_node}")
474
+ key_node.add_next_sibling(string_value_node)
475
+ else
476
+ @logger.info("\t'Key' node with content #{key} already exists.")
477
+ existing_string_value_node = key_node.xpath("following-sibling::*").first
478
+ if existing_string_value_node.name == 'string'
479
+ @logger.info("\tUpdating following string sibling value with #{value}")
480
+ existing_string_value_node.content = value
481
+ else
482
+ @logger.info("\tAdding next string sibling with content #{string_value_node}")
483
+ key_node.add_next_sibling(string_value_node)
484
+ end
485
+ end
486
+
487
+ File.open(plist_path, 'w') do |file|
488
+ @logger.info("\tWriting changes to plist: #{plist_path}")
489
+ file.puts Nokogiri::XML(doc.to_xml) { |x| x.noblanks }
490
+ end
491
+ end
492
+ end
493
+
494
+ def put_key_array_element(key, value, file_paths) # check if it appends to existing array
495
+ @logger.debug("put_key_array_element #{key} #{value} #{file_paths}")
496
+ file_paths.each do |file_path|
497
+ file_path = resolve_absolute_paths([file_path]).first
498
+ doc = Nokogiri::XML(IO.read(file_path))
499
+ key_node = doc.search("//dict//key[text() = '#{key}']").first
500
+ string_app_group_value = Nokogiri::XML::Node.new("string", doc)
501
+ string_app_group_value.content = value
502
+ if key_node == nil
503
+ @logger.info("\tAdding 'key' node with content #{key}")
504
+ key_node = Nokogiri::XML::Node.new("key", doc)
505
+ key_node.content = key
506
+ array_node = Nokogiri::XML::Node.new("array", doc)
507
+ array_node.add_child(string_app_group_value)
508
+
509
+ doc.xpath("//dict").first.add_child(key_node)
510
+ key_node.add_next_sibling(array_node)
511
+ else
512
+ @logger.info("\t'Key' node with content #{key} already exists.")
513
+ array_node = key_node.xpath("following-sibling::*").first
514
+ if array_node.name == 'array'
515
+ @logger.info("\tFollowing array sibling already exists")
516
+ if array_node.xpath("//string[text() = '#{value}']").first
517
+ @logger.info("\tArray string element with content #{value} already exists")
518
+ else
519
+ @logger.info("\tAdding child string element with content #{value}")
520
+ array_node.add_child(string_app_group_value)
521
+ end
522
+ else
523
+ @logger.info("\tFollowing array sibling is missing. Adding array node containing a string element.")
524
+ array_node = Nokogiri::XML::Node.new("array", doc)
525
+ array_node.add_child(string_app_group_value)
526
+ key_node.add_next_sibling(array_node)
527
+ end
528
+ end
529
+
530
+ File.open(file_path, 'w') do |file|
531
+ @logger.info("\tWriting changes to entitlements: #{file_path}")
532
+ file.puts Nokogiri::XML(doc.to_xml) { |x| x.noblanks }
533
+ end
534
+ end
535
+ end
489
536
  end
@@ -1,3 +1,3 @@
1
1
  module Mmine
2
- VERSION = "0.7.9"
2
+ VERSION = "0.8.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mmine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.9
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrey Kadochnikov