|
7 | 7 | using System.IO.Compression;
|
8 | 8 | using System.Linq;
|
9 | 9 | using System.Text;
|
| 10 | +using System.Text.Json; |
10 | 11 | using System.Text.RegularExpressions;
|
11 | 12 | using Microsoft.Android.Build;
|
12 | 13 | using Microsoft.Build.Framework;
|
@@ -381,7 +382,13 @@ public ApkBuilder(TaskLoggingHelper logger)
|
381 | 382 | cmakeLists = cmakeLists.Replace("%Defines%", defines.ToString());
|
382 | 383 |
|
383 | 384 | File.WriteAllText(Path.Combine(OutputDir, "CMakeLists.txt"), cmakeLists);
|
384 |
| - File.WriteAllText(Path.Combine(OutputDir, monodroidSource), Utils.GetEmbeddedResource(monodroidSource)); |
| 385 | + |
| 386 | + string monodroidContent = Utils.GetEmbeddedResource(monodroidSource); |
| 387 | + if (IsCoreCLR) |
| 388 | + { |
| 389 | + monodroidContent = RenderMonodroidCoreClrTemplate(monodroidContent); |
| 390 | + } |
| 391 | + File.WriteAllText(Path.Combine(OutputDir, monodroidSource), monodroidContent); |
385 | 392 |
|
386 | 393 | AndroidProject project = new AndroidProject("monodroid", runtimeIdentifier, AndroidNdk, logger);
|
387 | 394 | project.GenerateCMake(OutputDir, MinApiLevel, StripDebugSymbols);
|
@@ -639,4 +646,66 @@ private static string NormalizePathToUnix(string path)
|
639 | 646 |
|
640 | 647 | [GeneratedRegex(@"\.(\d)")]
|
641 | 648 | private static partial Regex DotNumberRegex();
|
| 649 | + |
| 650 | + private string RenderMonodroidCoreClrTemplate(string monodroidContent) |
| 651 | + { |
| 652 | + // At the moment, we only set the AppContext properties, so it's all done here for simplicity. |
| 653 | + // If we need to add more rendering logic, we can refactor this method later. |
| 654 | + var appContextKeys = new StringBuilder(); |
| 655 | + appContextKeys.AppendLine(" appctx_keys[0] = \"RUNTIME_IDENTIFIER\";"); |
| 656 | + appContextKeys.AppendLine(" appctx_keys[1] = \"APP_CONTEXT_BASE_DIRECTORY\";"); |
| 657 | + appContextKeys.AppendLine(" appctx_keys[2] = \"HOST_RUNTIME_CONTRACT\";"); |
| 658 | + |
| 659 | + var appContextValues = new StringBuilder(); |
| 660 | + appContextValues.AppendLine(" appctx_values[0] = ANDROID_RUNTIME_IDENTIFIER;"); |
| 661 | + appContextValues.AppendLine(" appctx_values[1] = g_bundle_path;"); |
| 662 | + appContextValues.AppendLine(); |
| 663 | + appContextValues.AppendLine(" char contract_str[19];"); // 0x + 16 hex digits + '\0' |
| 664 | + appContextValues.AppendLine(" snprintf(contract_str, 19, \"0x%zx\", (size_t)(&g_host_contract));"); |
| 665 | + appContextValues.AppendLine(" appctx_values[2] = contract_str;"); |
| 666 | + appContextValues.AppendLine(); |
| 667 | + |
| 668 | + // Parse runtime config properties and add them to the AppContext keys and values. |
| 669 | + Dictionary<string, string> configProperties = ParseRuntimeConfigProperties(); |
| 670 | + int hardwiredAppContextProperties = 3; // For the hardwired AppContext keys and values above. |
| 671 | + int i = 0; |
| 672 | + foreach ((string key, string value) in configProperties) |
| 673 | + { |
| 674 | + appContextKeys.AppendLine($" appctx_keys[{i + hardwiredAppContextProperties}] = \"{key}\";"); |
| 675 | + appContextValues.AppendLine($" appctx_values[{i + hardwiredAppContextProperties}] = \"{value}\";"); |
| 676 | + i++; |
| 677 | + } |
| 678 | + |
| 679 | + // Replace the template placeholders. |
| 680 | + string updatedContent = monodroidContent.Replace("%AppContextPropertyCount%", (configProperties.Count + hardwiredAppContextProperties).ToString()) |
| 681 | + .Replace("%AppContextKeys%", appContextKeys.ToString().TrimEnd()) |
| 682 | + .Replace("%AppContextValues%", appContextValues.ToString().TrimEnd()); |
| 683 | + return updatedContent; |
| 684 | + } |
| 685 | + |
| 686 | + private Dictionary<string, string> ParseRuntimeConfigProperties() |
| 687 | + { |
| 688 | + var configProperties = new Dictionary<string, string>(); |
| 689 | + string runtimeConfigPath = Path.Combine(AppDir ?? throw new InvalidOperationException("AppDir is not set"), $"{ProjectName}.runtimeconfig.json"); |
| 690 | + |
| 691 | + try |
| 692 | + { |
| 693 | + string jsonContent = File.ReadAllText(runtimeConfigPath); |
| 694 | + using JsonDocument doc = JsonDocument.Parse(jsonContent); |
| 695 | + JsonElement root = doc.RootElement; |
| 696 | + if (root.TryGetProperty("runtimeOptions", out JsonElement runtimeOptions) && runtimeOptions.TryGetProperty("configProperties", out JsonElement propertiesJson)) |
| 697 | + { |
| 698 | + foreach (JsonProperty property in propertiesJson.EnumerateObject()) |
| 699 | + { |
| 700 | + configProperties[property.Name] = property.Value.ToString(); |
| 701 | + } |
| 702 | + } |
| 703 | + } |
| 704 | + catch (Exception ex) |
| 705 | + { |
| 706 | + logger.LogMessage(MessageImportance.High, $"Error while parsing runtime config at {runtimeConfigPath}: {ex.Message}"); |
| 707 | + } |
| 708 | + |
| 709 | + return configProperties; |
| 710 | + } |
642 | 711 | }
|
0 commit comments