Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: WireUpControls throws exception in net8.0-android #3851

Closed
gerardvanderkruijs opened this issue Jul 8, 2024 · 20 comments
Closed

[Bug]: WireUpControls throws exception in net8.0-android #3851

gerardvanderkruijs opened this issue Jul 8, 2024 · 20 comments
Labels

Comments

@gerardvanderkruijs
Copy link

gerardvanderkruijs commented Jul 8, 2024

Describe the bug 🐞

When calling ReactiveUI.ControlFetcherMixin.WireUpControls() in a .NET 8 Android app (net8.0-android) in non-debug configuration, even though the correct resource ID is specified, a MissingFieldException is thrown.

This issue was fixed with bug report #3714 , but only for Debug builds by the looks of it. When deploying Release builds the exception is still present.
I narrowed it down to one specific .csproj property, that is this one:

<AndroidLinkMode>SdkOnly</AndroidLinkMode>

When I change this to <AndroidLinkMode>None</AndroidLinkMode> it all works perfectly.

Stracktrace:

07-08 10:38:08.523 I/MonoDroid( 5668): UNHANDLED EXCEPTION:
07-08 10:38:08.525 I/MonoDroid( 5668): Android.Runtime.JavaProxyThrowable: Exception_WasThrown, Android.Runtime.JavaProxyThrowable
07-08 10:38:08.525 I/MonoDroid( 5668): 
07-08 10:38:08.525 I/MonoDroid( 5668):   --- End of managed Android.Runtime.JavaProxyThrowable stack trace ---
07-08 10:38:08.525 I/MonoDroid( 5668): android.runtime.JavaProxyThrowable: [System.MissingFieldException]: Failed to wire up the Property XXXXXXX to a View in your layout with a corresponding identifier
07-08 10:38:08.525 I/MonoDroid( 5668): 	at ReactiveUI.ControlFetcherMixin.WireUpControls(Unknown Source:0)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at XXXXXXXX.StartActivity.OnCreate(Unknown Source:0)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_(Unknown Source:0)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PPL_V(Unknown Source:0)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at crc64763ea4d78b8a71b3.StartActivity.n_onCreate(Native Method)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at crc64763ea4d78b8a71b3.StartActivity.onCreate(StartActivity.java:42)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at android.app.Activity.performCreate(Activity.java:8595)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at android.app.Activity.performCreate(Activity.java:8573)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1456)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3764)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3922)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at android.os.Handler.dispatchMessage(Handler.java:106)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at android.os.Looper.loopOnce(Looper.java:205)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at android.os.Looper.loop(Looper.java:294)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at android.app.ActivityThread.main(ActivityThread.java:8177)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at java.lang.reflect.Method.invoke(Native Method)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
07-08 10:38:08.525 I/MonoDroid( 5668): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
07-08 10:38:08.525 I/MonoDroid( 5668): 

project .csproj file

<Project Sdk="Microsoft.NET.Sdk">
	<PropertyGroup>
		<TargetFramework>net8.0-android</TargetFramework>
		<SupportedOSPlatformVersion>24</SupportedOSPlatformVersion>
		<RootNamespace>ReactiveUI_WireUpControls_Issue</RootNamespace>
		<OutputType>Exe</OutputType>
		<Nullable>enable</Nullable>
		<ImplicitUsings>enable</ImplicitUsings>
		<ApplicationId>com.companyname.ReactiveUI_WireUpControls_Issue</ApplicationId>
		<ApplicationVersion>1</ApplicationVersion>
		<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
		<Configurations>Debug;Release</Configurations>
		<WarningLevel>4</WarningLevel>
		<ReleaseVersion>1.0.0</ReleaseVersion>
		<RuntimeIdentifiers>android-arm;android-arm64;android-x86;android-x64</RuntimeIdentifiers>
		<AndroidDexTool>d8</AndroidDexTool>
		<EnableLLVM>false</EnableLLVM>
		<AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
		<BundleAssemblies>false</BundleAssemblies>
	</PropertyGroup>
	<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
		<DebugSymbols>true</DebugSymbols>
		<DebugType>full</DebugType>
		<Optimize>false</Optimize>
		<ErrorReport>prompt</ErrorReport>
		<ConsolePause>false</ConsolePause>
		<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
		<AndroidUseAapt2>true</AndroidUseAapt2>
		<AndroidUseSharedRuntime>true</AndroidUseSharedRuntime>
		<AndroidEnableSGenConcurrent>false</AndroidEnableSGenConcurrent>
		<AndroidLinkMode>None</AndroidLinkMode>
	</PropertyGroup>
	<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
		<DebugSymbols>false</DebugSymbols>
		<DebugType>None</DebugType>
		<Optimize>true</Optimize>
		<AndroidLinkMode>SdkOnly</AndroidLinkMode>
	</PropertyGroup>
	<ItemGroup>
		<PackageReference Include="ReactiveUI" Version="19.6.12" />
	</ItemGroup>
</Project>

Step to reproduce

  1. Install .NET 8. (I installed 8.0.302)
  2. Create a new net8.0-android project using dotnet new android command.
  3. Add reference to ReactiveUI version 19.6.12
  4. Open MainActivity.cs and change it so that MainActivity inherits ReactiveUI.ReactiveActivity
public class MainActivity : ReactiveActivity
  1. Assign an ID(android:id) to the TextView in activity_main.xml and add a member to MainActivity.cs to wire it up.
    <TextView 
        android:id="@+id/app_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="@string/app_text"
    />
    [WireUpResource("app_text")]
    public TextView AppText { get; private set; }
  1. Add a call to WireUpControls() after SetContentView() in OnCreate().
this.WireUpControls();
  1. Build and launch application with Release configuration
  2. MissingFieldException is thrown from WireUpControls().
  3. Also you could change AndroidLinkMode to SdkOnly in the Debug config, this will result in same exception.

Reproduction repository

https://github.com/gerardvanderkruijs/ReactiveUI-WireUpControls-Issue

Expected behavior

After launching the application In Release configuration, the TextView should be wired up correctly, and the initial screen should be displayed.
AndroidLinkMode set to SdkOnly should not throw a MissingFieldException.

Screenshots 🖼️

No response

IDE

Rider macOS

Operating system

Android

Version

13

Device

Emulator

ReactiveUI Version

19.6.12

Additional information ℹ️

Since this report is almost identical to #3714 I mainly used all the info and sample project provided by @tommy10344, so thank you for that :-)

@gerardvanderkruijs
Copy link
Author

@ChrisPulman Do you perhaps have any clue about this? You fixed the same issue in #3714, so maybe your magic can solve this issue too 😇

@ChrisPulman
Copy link
Member

Hi @gerardvanderkruijs I will try to take a look this weekend, unfortunately I am away until Friday evening so don't think I'll get much time until then.

@gerardvanderkruijs
Copy link
Author

Hi @ChrisPulman , no worries that’s perfect! Thank you so much 🙏

@ChrisPulman
Copy link
Member

@gerardvanderkruijs Just wondering if there is a specific requirement to use V19.6.12

@ChrisPulman
Copy link
Member

@gerardvanderkruijs I did some research and as we are using reflection within ReactiveUI using linkers with AOT Compilation will not work as desired, the _Microsoft.Android.Resource.Designer.dll gets stripped of its code by being trimmed. I will see if I can find a way to do the same thing without using reflection. It seems that the _Microsoft.Android.Resource.Designer library may also not AOT friendly so may need to see what can be done about that first.

If the legacy AndroidLinkMode setting is used, both SdkOnly and Full will default to equivalent linker settings:

<PublishTrimmed>true</PublishTrimmed>
<TrimMode>link</TrimMode>

With AndroidLinkMode=SdkOnly only BCL and SDK assemblies marked with %(Trimmable) will be linked at the member level. AndroidLinkMode=Full will set %(TrimMode)=link on all .NET assemblies similar to the example in the trimming documentation.

It is recommended to migrate to the new linker settings, as AndroidLinkMode will eventually be deprecated.

For the time being in your project I would set the following:

<IsTrimmable>True</IsTrimmable>
<TrimMode>link</TrimMode>
<PublishTrimmed>false</PublishTrimmed> // will remove the resources if true
<RunAOTCompilation>false</RunAOTCompilation> // will remove the resources if true

Then set the following:

[DynamicDependency(DynamicallyAccessedMemberTypes.All, "ResourceConstant", "_Microsoft.Android.Resource.Designer")]
protected override void OnCreate(Bundle? savedInstanceState)

Further Documentation can be found here Linking with .NET Android

@ChrisPulman
Copy link
Member

Trimming incompatibilities
Some further pointers to why Trimming can fail

@gerardvanderkruijs
Copy link
Author

Hi @ChrisPulman ,

Thanks for the super clear explanation and for the (temp) solution!
I've been playing around this morning and everything seems to be working alright again now 🙌

The reason we're still using 19.6.12 is because 20.x.x results in another error in our Android project.
Of course this is not the thread for it, but it throws the following exception:

System.MethodAccessException: Method `ReactiveUI.ControlFetcherMixin.GetWireUpMembers(object,ReactiveUI.ControlFetcherMixin/ResolveStrategy)' is inaccessible from method `ReactiveUI.AndroidX.ControlFetcherMixin.WireUpControls(AndroidX.Fragment.App.Fragment,Android.Views.View,ReactiveUI.ControlFetcherMixin/ResolveStrategy)'
   at ReactiveUI.AndroidX.ControlFetcherMixin.WireUpControls(Fragment fragment, View inflatedView, ResolveStrategy resolveMembers) in /_/src/ReactiveUI.AndroidX/ControlFetcherMixin.cs:line 35
   at ***.OnViewCreated(View view, Bundle savedInstanceState) in ***.cs:line 84
   at AndroidX.Fragment.App.Fragment.n_OnViewCreated_Landroid_view_View_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, IntPtr native_view, IntPtr native_savedInstanceState) in C:\a\_work\2\s\generated\androidx.fragment.fragment\obj\Release\net7.0-android\generated\src\AndroidX.Fragment.App.Fragment.cs:line 2742
   at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PPLL_V(_JniMarshal_PPLL_V callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, IntPtr p1) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:line 198

Also, there is no 20.x.x version of the ReactiveUI.AndroidX package, the last version is 19.6.12, I assume we still need this package to wire up our controls in our .NET Android project?

@ChrisPulman
Copy link
Member

ReactiveUI.AndroidX was aimed at pre net6.0 targeted versions of Android, as far as I am aware you should be able to achieve the same with just the ReactiveUI base package. I will certainly check again though.

@gerardvanderkruijs
Copy link
Author

Ah okay! Good to know.
When I remove the ReactiveUI.AndroidX package there's a lot of errors, which is not necessarily a big issue if I would be able to fix them.
For example, where did the class ReactiveRecyclerViewViewHolder go? Or ReactiveRecyclerViewAdapter, ReactiveAppCompatActivity and so on.

@gerardvanderkruijs
Copy link
Author

@ChrisPulman Were you by any chance able yet to have a look at this?
The v19.x version of the ReactiveUI package is slowly causing a dependency issue for us, with conflicting versions because of other Android packages.
I would be happy to remove the ReactiveUI.AndroidX but this is causing a lot of issues for us right now.
Any help would be super appreciated! 🙏

ChrisPulman added a commit that referenced this issue Sep 1, 2024
Only supports Net 8.0 plus
#3851
@ChrisPulman
Copy link
Member

@ChrisPulman Were you by any chance able yet to have a look at this? The v19.x version of the ReactiveUI package is slowly causing a dependency issue for us, with conflicting versions because of other Android packages. I would be happy to remove the ReactiveUI.AndroidX but this is causing a lot of issues for us right now. Any help would be super appreciated! 🙏

@gerardvanderkruijs Hi, I was waiting for the latest release with net 8 support to reproduce the AndriodX functionality, they released the base packages on the 29th hopefully we can get a release out soon.

Are we able to close this issue now?

@gerardvanderkruijs
Copy link
Author

Hi @ChrisPulman!
I think we can't close this issue until this exception is resolved.
I don't see any package updates yet, but will keep an eye out!

For now the ReactiveUI package version 20.x.x still throws the MissingFieldException on net8.0-android projects.

ChrisPulman added a commit that referenced this issue Sep 2, 2024
<!-- Please be sure to read the
[Contribute](https://github.com/reactiveui/reactiveui#contribute)
section of the README -->

**What kind of change does this PR introduce?**
<!-- Bug fix, feature, docs update, ... -->

Feature

**What is the current behavior?**
<!-- You can also link to an open issue here. -->

#3851

**What is the new behavior?**
<!-- If this is a feature change -->

Functionality ported from the Mono Android TFM version that went out of
support.
Only supports Net 8.0 plus with the latest packages released on 29th
August 2024

**What might this PR break?**

No support for older targets if upgrading from the legacy package.

**Please check if the PR fulfills these requirements**
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been added / updated (for bug fixes / features)

**Other information**:
@gerardvanderkruijs
Copy link
Author

Hi @ChrisPulman ,
Any news on this issue and the release of the package updates?

@glennawatson
Copy link
Contributor

working on some of that as we speak now, We had issues getting issued a certificate which has been solved. Hopefully today but can't promise depending on technical glitches I'm having

@gerardvanderkruijs
Copy link
Author

Ah amazing @glennawatson !
No promises needed for today :-) It would be perfectly fine if it's next week or in a few weeks, just checking in every now and again.
I'll keep an eye out on the nuget packages!
Thanks again

@glennawatson
Copy link
Contributor

I'm chasing up some certificate weirdness with the nuget team. Very strange stuff happening.

@glennawatson
Copy link
Contributor

Everything should be out now

@gerardvanderkruijs
Copy link
Author

Hi @glennawatson (and maybe also @ChrisPulman ),

I've installed the latest package releases (ReactiveUI and ReactiveUI.AndroidX v20.1.52).

On Android (net8.0-android) everything seems to be working again, which is amazing! 🥰 All the AndroidX classes (for example ReactiveRecyclerViewViewHolder, ReactiveRecyclerViewAdapter etc.) are back and working perfectly!

One small question regarding ReactiveUI.AndroidX, any reason why (for example) Xamarin.AndroidX.Lifecycle.LiveData is still on v2.8.4.1?
Reference:

<PackageVersion Include="Xamarin.AndroidX.Lifecycle.LiveData" Version="2.8.4.1" />

We use quite a lot of Firebase and GooglePlayServices packages and we're stuck again in a dependency loop because of version conflicts. If it's not too much to ask, maybe these can be updated as well in the next update?

For the rest, I'm closing this issue ☺️ because it's very very done! ✅

@glennawatson
Copy link
Contributor

Probably worth opening a new issue with the dependency issue with the other package for tracking

Copy link

github-actions bot commented Oct 3, 2024

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 3, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

3 participants