`DOTNET_STARTUP_HOOKS` from `@(AndroidEnvironment)` files is silently overwritten
- Dominant language
- C#
- Stars
- 2.1k
- Forks
- 579
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 257
Description
### Description
Both the HotReload targets (`Microsoft.Android.Sdk.HotReload.targets`) and the trimmable typemap targets (`Microsoft.Android.Sdk.TypeMap.Trimmable.targets`) compose `DOTNET_STARTUP_HOOKS` only from `@(RuntimeEnvironmentVariable)` items. However, users can also declare environment variables via `@(AndroidEnvironment)` text files:
```
DOTNET_STARTUP_HOOKS=MyStartupHook.dll
```
When the build targets run, they do:
```xml
```
This replaces the `@(RuntimeEnvironmentVariable)` value but never reads or merges values from `@(AndroidEnvironment)` files. The user's startup hook is silently dropped.
### Affected targets
1. **`_AndroidConfigureHotReloadEnvironment`** in `Microsoft.Android.Sdk.HotReload.targets` ([L48-49](https://github.com/dotnet/android/blob/610601670e841a466cc22c17b344c328aa2d4163/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.HotReload.targets#L48-L49)) — replaces `DOTNET_STARTUP_HOOKS` without composing.
2. **`_ConfigureTrimmableTypeMapStartupHook`** in `Microsoft.Android.Sdk.TypeMap.Trimmable.targets` (PR #11181) — composes `@(RuntimeEnvironmentVariable)` entries but ignores `@(AndroidEnvironment)` files.
### Expected behavior
All `DOTNET_STARTUP_HOOKS` values — regardless of source — should be merged (colon-separated) into the final environment written to the app.
### Suggested approach
Introduce a new `@(_AndroidDotnetStartupHooks)` item group as the single collection point. A target running before `_GenerateEnvironmentFiles` merges **all three sources**:
1. **`@(_AndroidDotnetStartupHooks)`** — internal contributors (HotReload, trimmable typemap) append their assembly names here instead of directly manipulating `@(RuntimeEnvironmentVariable)`
2. **`@(RuntimeEnvironmentVariable)`** (filtered for `DOTNET_STARTUP_HOOKS`) — values passed in externally, e.g. by `dotnet watch`
3. **`@(AndroidEnvironment)`** files — parsed for `DOTNET_STARTUP_HOOKS=...` lines
The target then:
- Removes any `DOTNET_STARTUP_HOOKS` from `@(RuntimeEnvironmentVariable)`
- Strips `DOTNET_STARTUP_HOOKS=...` lines from `@(AndroidEnvironment)` file content (or leaves them and deduplicates — TBD)
- Joins all collected values with `:` into a single `@(RuntimeEnvironmentVariable)` entry
This approach:
- Eliminates the fragile remove-then-add pattern each contributor currently does
- Makes composition order-independent — no target needs to know about other contributors
- Avoids duplicates naturally (items are distinct assembly names)
- Starts as private (`_` prefix) with the option to make it public and documented later
### Context
Discussed in https://github.com/dotnet/android/pull/11181#discussion_r3126593242
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.