@@ -30,6 +30,23 @@ namespace GooglePlayServices {
30
30
/// </summary>
31
31
internal class GradleTemplateResolver {
32
32
33
+ /// <summary>
34
+ /// Path of the Gradle properties file.
35
+ /// Available only from Unity version 2019.3 onwards
36
+ /// </summary>
37
+ public static string GradlePropertiesTemplatePath =
38
+ Path . Combine ( SettingsDialog . AndroidPluginsDir , "gradleTemplate.properties" ) ;
39
+
40
+ /// <summary>
41
+ /// Line that indicates the start of the injected properties block in properties template.
42
+ /// </summary>
43
+ private const string PropertiesStartLine = "# Android Resolver Properties Start" ;
44
+
45
+ /// <summary>
46
+ /// Line that indicates the end of the injected properties block in properties template.
47
+ /// </summary>
48
+ private const string PropertiesEndLine = "# Android Resolver Properties End" ;
49
+
33
50
/// <summary>
34
51
/// Path of the Gradle template file.
35
52
/// </summary>
@@ -52,6 +69,13 @@ internal class GradleTemplateResolver {
52
69
private const string ReposInjectionLine =
53
70
@".*apply plugin: 'com\.android\.(application|library)'.*" ;
54
71
72
+ /// <summary>
73
+ /// Token that indicates where gradle properties should initially be injected.
74
+ /// If this isn't present in the properties template, properties will not be
75
+ /// injected or they'll be removed.
76
+ /// </summary>
77
+ private const string PropertiesInjectionLine = @"ADDITIONAL_PROPERTIES" ;
78
+
55
79
/// <summary>
56
80
/// Line that indicates the start of the injected dependencies block in the template.
57
81
/// </summary>
@@ -261,6 +285,149 @@ public List<string> ProcessLine(string line, out bool injectionApplied) {
261
285
}
262
286
}
263
287
288
+ /// <summary>
289
+ /// Patch file contents by injecting custom data.
290
+ /// </summary>
291
+ /// <param name="filePath">Path to file to modify</param>
292
+ /// <param name="fileDescription">Used in logs for describing the file</param>
293
+ /// <param name="analyticsReportName">Name used in analytics logs</param>
294
+ /// <param name="analyticsReportUrlToken">Token used in forming analytics path</param>
295
+ /// <param name="injectors">Array of text injectors</param>
296
+ /// <param name="resolutionMeasurementProperties">used in analytics reporting</param>
297
+ /// <returns>true if successful, false otherwise.</returns>
298
+ private static bool PatchFile ( string filePath ,
299
+ string fileDescription ,
300
+ string analyticsReportName ,
301
+ string analyticsReportUrlToken ,
302
+ TextFileLineInjector [ ] injectors ,
303
+ ICollection < KeyValuePair < string , string > >
304
+ resolutionMeasurementParameters ) {
305
+ IEnumerable < string > lines ;
306
+ try {
307
+ lines = File . ReadAllLines ( filePath ) ;
308
+ } catch ( Exception ex ) {
309
+ PlayServicesResolver . analytics . Report (
310
+ "/resolve/" + analyticsReportUrlToken + "/failed/templateunreadable" ,
311
+ analyticsReportName + " Resolve: Failed Template Unreadable" ) ;
312
+ PlayServicesResolver . Log (
313
+ String . Format ( "Unable to patch {0} ({1})" , fileDescription , ex . ToString ( ) ) ,
314
+ level : LogLevel . Error ) ;
315
+ return false ;
316
+ }
317
+
318
+ // Lines that will be written to the output file.
319
+ var outputLines = new List < string > ( ) ;
320
+ foreach ( var line in lines ) {
321
+ var currentOutputLines = new List < string > ( ) ;
322
+ foreach ( var injector in injectors ) {
323
+ bool injectionApplied = false ;
324
+ currentOutputLines = injector . ProcessLine ( line , out injectionApplied ) ;
325
+ if ( injectionApplied || currentOutputLines . Count == 0 ) break ;
326
+ }
327
+ outputLines . AddRange ( currentOutputLines ) ;
328
+ }
329
+
330
+ var inputText = String . Join ( "\n " , ( new List < string > ( lines ) ) . ToArray ( ) ) + "\n " ;
331
+ var outputText = String . Join ( "\n " , outputLines . ToArray ( ) ) + "\n " ;
332
+
333
+ if ( inputText == outputText ) {
334
+ PlayServicesResolver . Log ( String . Format ( "No changes to {0}" , fileDescription ) ,
335
+ level : LogLevel . Verbose ) ;
336
+ return true ;
337
+ }
338
+ return WriteToFile ( filePath , fileDescription , outputText ,
339
+ analyticsReportName , analyticsReportUrlToken ,
340
+ resolutionMeasurementParameters ) ;
341
+ }
342
+
343
+ /// <summary>
344
+ /// Write new contents to a file on disk
345
+ /// </summary>
346
+ /// <param name="filePath">Path to file to modify</param>
347
+ /// <param name="fileDescription">Used in logs for describing the file</param>
348
+ /// <param name="outputText">Updated contents to write to the file</param>
349
+ /// <param name="analyticsReportName">Name used in analytics logs</param>
350
+ /// <param name="analyticsReportUrlToken">Token used in forming analytics path</param>
351
+ /// <param name="resolutionMeasurementProperties">used in analytics reporting</param>
352
+ /// <returns>true if successful, false otherwise.</returns>
353
+ private static bool WriteToFile ( string filePath ,
354
+ string fileDescription ,
355
+ string outputText ,
356
+ string analyticsReportName ,
357
+ string analyticsReportUrlToken ,
358
+ ICollection < KeyValuePair < string , string > >
359
+ resolutionMeasurementParameters ) {
360
+ if ( ! FileUtils . CheckoutFile ( filePath , PlayServicesResolver . logger ) ) {
361
+ PlayServicesResolver . Log (
362
+ String . Format ( "Failed to checkout '{0}', unable to patch the file." ,
363
+ filePath ) , level : LogLevel . Error ) ;
364
+ PlayServicesResolver . analytics . Report (
365
+ "/resolve/" + analyticsReportUrlToken + "/failed/checkout" ,
366
+ analyticsReportName + " Resolve: Failed to checkout" ) ;
367
+ return false ;
368
+ }
369
+ PlayServicesResolver . Log (
370
+ String . Format ( "Writing updated {0}" , fileDescription ) ,
371
+ level : LogLevel . Verbose ) ;
372
+ try {
373
+ File . WriteAllText ( filePath , outputText ) ;
374
+ PlayServicesResolver . analytics . Report (
375
+ "/resolve/" + analyticsReportUrlToken + "/success" ,
376
+ resolutionMeasurementParameters ,
377
+ analyticsReportName + " Resolve Success" ) ;
378
+ } catch ( Exception ex ) {
379
+ PlayServicesResolver . analytics . Report (
380
+ "/resolve/" + analyticsReportUrlToken + "/failed/write" ,
381
+ analyticsReportName + " Resolve: Failed to write" ) ;
382
+ PlayServicesResolver . Log (
383
+ String . Format ( "Unable to patch {0} ({1})" , fileDescription ,
384
+ ex . ToString ( ) ) , level : LogLevel . Error ) ;
385
+ return false ;
386
+ }
387
+ return true ;
388
+ }
389
+
390
+ /// <summary>
391
+ /// Inject properties in the gradle properties template file.
392
+ /// Because of a change in structure of android projects built with
393
+ /// Unity 2019.3 and above, the correct way to enable jetifier and
394
+ /// Android X is by updating the gradle properties template.
395
+ /// </summary>
396
+ /// <returns>true if successful, false otherwise.</returns>
397
+ public static bool InjectProperties ( ) {
398
+ var resolutionMeasurementParameters =
399
+ PlayServicesResolver . GetResolutionMeasurementParameters ( null ) ;
400
+ PlayServicesResolver . analytics . Report (
401
+ "/resolve/gradleproperties" , resolutionMeasurementParameters ,
402
+ "Gradle Properties Resolve" ) ;
403
+ var propertiesLines = new List < string > ( ) ;
404
+ // Lines to add Custom Gradle properties template to enable
405
+ // jetifier and androidx
406
+ propertiesLines . AddRange ( new [ ] {
407
+ "android.useAndroidX=true" ,
408
+ "android.enableJetifier=true" ,
409
+ } ) ;
410
+ var propertiesFileDescription = String . Format (
411
+ "gradle properties template" + GradlePropertiesTemplatePath ) ;
412
+ TextFileLineInjector [ ] propertiesInjectors = new [ ] {
413
+ new TextFileLineInjector ( PropertiesInjectionLine ,
414
+ PropertiesStartLine , PropertiesEndLine ,
415
+ propertiesLines ,
416
+ "Properties" ,
417
+ propertiesFileDescription )
418
+ } ;
419
+ if ( ! PatchFile ( GradlePropertiesTemplatePath , propertiesFileDescription ,
420
+ "Gradle Properties" , "gradleproperties" ,
421
+ propertiesInjectors ,
422
+ resolutionMeasurementParameters ) ) {
423
+ PlayServicesResolver . Log (
424
+ String . Format ( "Unable to patch " + propertiesFileDescription ) ,
425
+ level : LogLevel . Error ) ;
426
+ return false ;
427
+ }
428
+ return true ;
429
+ }
430
+
264
431
/// <summary>
265
432
/// Inject / update dependencies in the gradle template file.
266
433
/// </summary>
@@ -328,14 +495,18 @@ public static bool InjectDependencies(ICollection<Dependency> dependencies) {
328
495
var repoLines = new List < string > ( ) ;
329
496
// Optionally enable the jetifier.
330
497
if ( SettingsDialog . UseJetifier && dependencies . Count > 0 ) {
331
- repoLines . AddRange ( new [ ] {
332
- "([rootProject] + (rootProject.subprojects as List)).each {" ,
333
- " ext {" ,
334
- " it.setProperty(\" android.useAndroidX\" , true)" ,
335
- " it.setProperty(\" android.enableJetifier\" , true)" ,
336
- " }" ,
337
- "}"
338
- } ) ;
498
+ // For Unity versions lower than 2019.3 add jetifier and AndroidX
499
+ // properties to custom main gradle template
500
+ if ( VersionHandler . GetUnityVersionMajorMinor ( ) < 2019.3f ) {
501
+ repoLines . AddRange ( new [ ] {
502
+ "([rootProject] + (rootProject.subprojects as List)).each {" ,
503
+ " ext {" ,
504
+ " it.setProperty(\" android.useAndroidX\" , true)" ,
505
+ " it.setProperty(\" android.enableJetifier\" , true)" ,
506
+ " }" ,
507
+ "}"
508
+ } ) ;
509
+ }
339
510
}
340
511
repoLines . AddRange ( PlayServicesResolver . GradleMavenReposLines ( dependencies ) ) ;
341
512
@@ -352,51 +523,9 @@ public static bool InjectDependencies(ICollection<Dependency> dependencies) {
352
523
PlayServicesResolver . PackagingOptionsLines ( dependencies ) ,
353
524
"Packaging Options" , fileDescription ) ,
354
525
} ;
355
- // Lines that will be written to the output file.
356
- var outputLines = new List < string > ( ) ;
357
- foreach ( var line in lines ) {
358
- var currentOutputLines = new List < string > ( ) ;
359
- foreach ( var injector in injectors ) {
360
- bool injectionApplied = false ;
361
- currentOutputLines = injector . ProcessLine ( line , out injectionApplied ) ;
362
- if ( injectionApplied || currentOutputLines . Count == 0 ) break ;
363
- }
364
- outputLines . AddRange ( currentOutputLines ) ;
365
- }
366
- var inputText = String . Join ( "\n " , ( new List < string > ( lines ) ) . ToArray ( ) ) + "\n " ;
367
- var outputText = String . Join ( "\n " , outputLines . ToArray ( ) ) + "\n " ;
368
- if ( inputText == outputText ) {
369
- PlayServicesResolver . Log ( String . Format ( "No changes to {0}" , fileDescription ) ,
370
- level : LogLevel . Verbose ) ;
371
- return true ;
372
- }
373
- if ( ! FileUtils . CheckoutFile ( GradleTemplatePath , PlayServicesResolver . logger ) ) {
374
- PlayServicesResolver . Log (
375
- String . Format ( "Failed to checkout '{0}', unable to patch the file." ,
376
- GradleTemplatePath ) , level : LogLevel . Error ) ;
377
- PlayServicesResolver . analytics . Report (
378
- "/resolve/gradletemplate/failed/checkout" ,
379
- "Gradle Template Resolve: Failed to checkout" ) ;
380
- return false ;
381
- }
382
- PlayServicesResolver . Log (
383
- String . Format ( "Writing updated {0}" , fileDescription ) ,
384
- level : LogLevel . Verbose ) ;
385
- try {
386
- File . WriteAllText ( GradleTemplatePath , outputText ) ;
387
- PlayServicesResolver . analytics . Report (
388
- "/resolve/gradletemplate/success" , resolutionMeasurementParameters ,
389
- "Gradle Template Resolve Success" ) ;
390
- } catch ( Exception ex ) {
391
- PlayServicesResolver . analytics . Report (
392
- "/resolve/gradletemplate/failed/write" ,
393
- "Gradle Template Resolve: Failed to write" ) ;
394
- PlayServicesResolver . Log (
395
- String . Format ( "Unable to patch {0} ({1})" , fileDescription ,
396
- ex . ToString ( ) ) , level : LogLevel . Error ) ;
397
- return false ;
398
- }
399
- return true ;
526
+ return PatchFile ( GradleTemplatePath , fileDescription ,
527
+ "Gradle Template" , "gradletemplate" ,
528
+ injectors , resolutionMeasurementParameters ) ;
400
529
}
401
530
}
402
531
}
0 commit comments