jsuarezruiz / rive-maui

.NET MAUI runtime for Rive
MIT License
38 stars 3 forks source link

I got an exception when try to run on Android #1

Open reinierkops opened 8 months ago

reinierkops commented 8 months ago

When running the sample project on a physical Android device, I got this error:

`System.Reflection.TargetInvocationException: 'Exception has been thrown by the target of an invocation.'

[mono-rt] [ERROR] FATAL UNHANDLED EXCEPTION: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. [mono-rt] ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. [mono-rt] ---> System.TypeInitializationException: The type initializer for 'RiveSharp.Factory' threw an exception. [mono-rt] ---> System.DllNotFoundException: rive [mono-rt] at RiveSharp.Factory..cctor() in D:\Projects\rive-maui\src\RiveSharp\Factory.cs:line 22 [mono-rt] --- End of inner exception stack trace --- [mono-rt] at RiveSharp.Scene..ctor() in D:\Projects\rive-maui\src\RiveSharp\Scene.cs:line 28 [mono-rt] at RiveSharp.Views.RivePlayer..ctor() in D:\Projects\rive-maui\src\RiveSharp.Views.MAUI\RivePlayer.cs:line 169 [mono-rt] at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Constructor(Object obj, IntPtr args) [mono-rt] at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr) [mono-rt] --- End of inner exception stack trace --- [mono-rt] at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr) [mono-rt] at System.RuntimeType.CreateInstanceMono(Boolean nonPublic, Boolean wrapExceptions) [mono-rt] at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean wrapExceptions) [mono-rt] at System.Activator.CreateInstance(Type type, Boolean nonPublic, Boolean wrapExceptions) [mono-rt] at System.Activator.CreateInstance(Type type, Boolean nonPublic) [mono-rt] at System.Activator.CreateInstance(Type type) [mono-rt] at Microsoft.Maui.Controls.Xaml.CreateValuesVisitor.Visit(ElementNode node, INode parentNode) in D:\a_work\1\s\src\Controls\src\Xaml\CreateValuesVisitor.cs:line 102 [mono-rt] at Microsoft.Maui.Controls.Xaml.ElementNode.Accept(IXamlNodeVisitor visitor, INode parentNode) in D:\a_work\1\s\src\Controls\src\Xaml\XamlNode.cs:line 159 [mono-rt] at Microsoft.Maui.Controls.Xaml.ElementNode.Accept(IXamlNodeVisitor visitor, INode parentNode) in D:\a_work\1\s\src\Controls\src\Xaml\XamlNode.cs:line 155 [mono-rt] at Microsoft.Maui.Controls.Xaml.RootNode.Accept(IXamlNodeVisitor visitor, INode parentNode) in D:\a_work\1\s\src\Controls\src\Xaml\XamlNode.cs:line 212 [mono-rt] at Microsoft.Maui.Controls.Xaml.XamlLoader.Visit(RootNode rootnode, HydrationContext visitorContext, Boolean useDesignProperties) in D:\a_work\1\s\src\Controls\src\Xaml\XamlLoader.cs:line 207 [mono-rt] at Microsoft.Maui.Controls.Xaml.XamlLoader.Load(Object view, String xaml, Assembly rootAssembly, Boolean useDesignProperties) in D:\a_work\1\s\src\Controls\src\Xaml\XamlLoader.cs:line 78 [mono-rt] at Microsoft.Maui.Controls.Xaml.XamlLoader.Load(Object view, String xaml, Boolean useDesignProperties) in D:\a_work\1\s\src\Controls\src\Xaml\XamlLoader.cs:line 53 [mono-rt] at Microsoft.Maui.Controls.Xaml.XamlLoader.Load(Object view, Type callingType) in D:\a_work\1\s\src\Controls\src\Xaml\XamlLoader.cs:line 49 [mono-rt] at Microsoft.Maui.Controls.Xaml.Extensions.LoadFromXaml[MainPage](MainPage view, Type callingType) in D:\a_work\1\s\src\Controls\src\Xaml\ViewExtensions.cs:line 37 [mono-rt] at Viewer.MainPage.InitializeComponent() in D:\Projects\rive-maui\src\Viewer\Microsoft.Maui.Controls.SourceGen\Microsoft.Maui.Controls.SourceGen.CodeBehindGenerator\MainPage.xaml.sg.cs:line 22 [mono-rt] at Viewer.MainPage..ctor() in D:\Projects\rive-maui\src\Viewer\MainPage.xaml.cs:line 7 [mono-rt] at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Constructor(Object obj, IntPtr args) [mono-rt] at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr) [mono-rt] --- End of inner exception stack trace --- [mono-rt] at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr) [mono-rt] at System.RuntimeType.CreateInstanceMono(Boolean nonPublic, Boolean wrapExceptions) [mono-rt] at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean wrapExceptions) [mono-rt] at System.Activator.CreateInstance(Type type, Boolean nonPublic, Boolean wrapExceptions) [mono-rt] at System.Activator.CreateInstance(Type type, Boolean nonPublic) [mono-rt] at System.Activator.CreateInstance(Type type) [mono-rt] at Microsoft.Maui.Controls.ShellContent.<>cDisplayClass19_0.b__0() in D:\a_work\1\s\src\Controls\src\Core\Shell\ShellContent.cs:line 76 [mono-rt] at Microsoft.Maui.Controls.ElementTemplate.CreateContent() in D:\a_work\1\s\src\Controls\src\Core\ElementTemplate.cs:line 86 [mono-rt] at Microsoft.Maui.Controls.Internals.DataTemplateExtensions.CreateContent(DataTemplate self, Object item, BindableObject container) in D:\a_work\1\s\src\Controls\src\Core\DataTemplateExtensions.cs:line 23 [mono-rt] at Microsoft.Maui.Controls.ShellContent.Microsoft.Maui.Controls.IShellContentController.GetOrCreateContent() in D:\a_work\1\s\src\Controls\src\Core\Shell\ShellContent.cs:line 81 [mono-rt] at Microsoft.Maui.Controls.Platform.Compatibility.ShellSectionRenderer.OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) in D:\a_work\1\s\src\Controls\src\Core\Compatibility\Handlers\Shell\Android\ShellSectionRenderer.cs:line 124 [mono-rt] at AndroidX.Fragment.App.Fragment.n_OnCreateView_Landroid_view_LayoutInflater_Landroid_view_ViewGroup_Landroid_osBundle(IntPtr jnienv, IntPtr nativethis, IntPtr native_inflater, IntPtr native_container, IntPtr native_savedInstanceState) in C:\a_work\1\s\generated\androidx.fragment.fragment\obj\Release et6.0-android\generated\src\AndroidX.Fragment.App.Fragment.cs:line 2031 [mono-rt] at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PPLLL_L(_JniMarshal_PPLLL_L callback, IntPtr jnienv, IntPtr klazz, IntPtr p0, IntPtr p1, IntPtr p2) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:line 367`

Windows is running fine (after manualy copy the rive.dll to the AnyCPU folder (which I get an error on): image

hansmbakker commented 6 months ago

Android will need its own library file I guess.

I tried including the .so files from the Android library (https://repo1.maven.org/maven2/app/rive/rive-android/9.2.2/rive-android-9.2.2.aar) using the AndroidNativeLibrary build action (note: librive-android.so would need to be renamed to rive.so), but that doesn't work since that binary misses RiveSharpInterop.cpp.

I asked the Rive developers to publish a nuget package that supports more platforms than only win10.

hansmbakker commented 6 months ago

What I tried further:

  1. Install the Mobile development using c++ workload and Clang / LLVM components in Visual Studio
  2. restore submodule
  3. download and put premake5.exe in native folder
  4. run .\premake5.exe --os=android vs2022 from the native folder

    ⚠️ by default it will generate a project using Clang, and I don't know if that will work. It is possible to select different compilers using CLI parameters but I didn't try that since the rive-sharp says that Clang/LLVM features are being used.

  5. Optional: there is an updated file upstream at https://github.com/rive-app/rive-sharp/blob/main/native/RiveSharpInterop.cpp
  6. When trying to use Clang, I believe you need to modify 37-41 to be (clang doesn't use __declspec(dllexport)):
    #ifdef WINDOWS
    #define RIVE_DLL(RET) extern "C" __declspec(dllexport) RET __cdecl
    #else // WASM / ANDROID
    #define RIVE_DLL(RET) extern "C" __attribute__((visibility("default"))) RET __cdecl
    #endif
  7. open RiveSharpSample.sln
  8. disable all TargetFrameworks except net8.0-android for these projects to deal with the point that the rive project now won't build a Windows dll anymore:
    • RiveSharp.Views.MAUI
    • Viewer
    • StateMachineInputs

When trying to build the rive project in this solution, I now get these errors:

Build started at 00:55...
1>------ Build started: Project: rive, Configuration: Debug x64 ------
1>ANDROID_HOME=C:\Program Files (x86)\Android\android-sdk
1>ANDROID_SDK_ROOT=C:\Program Files (x86)\Android\android-sdk
1>ANT_HOME=
1>JAVA_HOME=C:\Program Files\Android\jdk\jdk-8.0.302.8-hotspot\jdk8u302-b08
1>NDK_ROOT=C:\\Microsoft\AndroidNDK\android-ndk-r23c
1>ld: error: obj/x64/Debug\animation_state.o: unable to find library from dependent library specifier: msvcrtd
1>ld: error: obj/x64/Debug\animation_state.o: unable to find library from dependent library specifier: oldnames
1>ld: error: obj/x64/Debug\animation_state_instance.o: unable to find library from dependent library specifier: msvcrtd
1>ld: error: obj/x64/Debug\animation_state_instance.o: unable to find library from dependent library specifier: oldnames
1>ld: error: obj/x64/Debug\blend_animation.o: unable to find library from dependent library specifier: msvcrtd
1>ld: error: obj/x64/Debug\blend_animation.o: unable to find library from dependent library specifier: oldnames
1>ld: error: obj/x64/Debug\blend_animation_1d.o: unable to find library from dependent library specifier: msvcrtd
1>ld: error: obj/x64/Debug\blend_animation_1d.o: unable to find library from dependent library specifier: oldnames
1>ld: error: obj/x64/Debug\blend_animation_direct.o: unable to find library from dependent library specifier: msvcrtd
1>ld: error: obj/x64/Debug\blend_animation_direct.o: unable to find library from dependent library specifier: oldnames
1>ld: error: obj/x64/Debug\blend_state.o: unable to find library from dependent library specifier: msvcrtd
1>ld: error: obj/x64/Debug\blend_state.o: unable to find library from dependent library specifier: oldnames
1>ld: error: obj/x64/Debug\blend_state_1d.o: unable to find library from dependent library specifier: msvcrtd
1>ld: error: obj/x64/Debug\blend_state_1d.o: unable to find library from dependent library specifier: oldnames
1>ld: error: obj/x64/Debug\blend_state_1d_instance.o: unable to find library from dependent library specifier: msvcrtd
1>ld: error: obj/x64/Debug\blend_state_1d_instance.o: unable to find library from dependent library specifier: oldnames
1>ld: error: obj/x64/Debug\blend_state_direct.o: unable to find library from dependent library specifier: msvcrtd
1>ld: error: obj/x64/Debug\blend_state_direct.o: unable to find library from dependent library specifier: oldnames
1>ld: error: obj/x64/Debug\blend_state_direct_instance.o: unable to find library from dependent library specifier: msvcrtd
1>ld: error: obj/x64/Debug\blend_state_direct_instance.o: unable to find library from dependent library specifier: oldnames
1>ld: error: too many errors emitted, stopping now (use -error-limit=0 to see all errors)
1>clang: error: linker command failed with exit code 1 (use -v to see invocation)
1>C:\Program Files\Microsoft Visual Studio\2022\Preview\MSBuild\Microsoft\VC\v170\Application Type\Android\3.0\Android.Common.targets(125,5): error MSB6006: "clang.exe" exited with code 1.
1>Done building project "rive.vcxproj" -- FAILED.

I was surprised to see it was asking for these msvcrtd and oldnames libraries and was not sure where to get them from. I thought it was more part of Microsoft's c++ build system and was not sure why clang would need them.

Please note - c++ and its ecosystem and different compilers are not my experience area, probably somebody else can better investigate this.

The readme from rive-sharp says that llvm/clang is the required compiler though.

matmork commented 5 months ago

For iOS and Android I suggest creating a binding project for the runtimes of each platform https://learn.microsoft.com/en-us/xamarin/ios/platform/binding-swift/walkthrough https://learn.microsoft.com/en-us/xamarin/android/platform/binding-java-library/binding-an-aar

Here is a very basic starting point https://github.com/Matmork/Rive-Maui

Note: Only iOS is showing the animation. Android is pretty close, some problems adding/displaying view. Maybe you can figure it out.

https://github.com/jsuarezruiz/rive-maui/assets/11912795/2bca270a-4606-427e-99db-6e9c064a7af1

hansmbakker commented 5 months ago

@Matmork cool that you're experimenting with this!

I saw you only included the Rive AAR for android and I believe that had dependencies on other libraries like Volley (not sure why it would need to call REST APIs though). Did you get any missing dependencies errors or were those other errors?

matmork commented 5 months ago

You are right, there were some missing dependencies. Added them to Rive.Android. Guess it needs Volley for fetching .riv files from url.

It's building and running, but I can't confirm if it's working or not. As mentioned I am having some problems adding a view/updating the content inside Maui's ContentViewHandler. I even tried just adding a red box, but nothing is showing.. I don't have the most experience with Android so I am pretty sure I am missing something. Or another approach is needed. See RiveViewHandler.cs PlatformView.AddView()

matmork commented 5 months ago

Changed to a ViewRenderer instead of ContentViewHandler. Can confirm its working

https://github.com/jsuarezruiz/rive-maui/assets/11912795/2923fc07-b963-4e0d-a2b2-099e8f2ac43b

hansmbakker commented 5 months ago

@Matmork wow, well done!

If you want to discuss further - let's create a discussion or issue at https://github.com/Matmork/Rive-Maui - to keep this issue related to the code in https://github.com/jsuarezruiz/rive-maui?

matmork commented 5 months ago

Sounds good. Would like to create a PR to add the bindings here but I am unsure how to structure the solution. There is still work to be done like exposing apis for events, state machine, dartboard etc. But it's a start!

hansmbakker commented 5 months ago

Would like to create a PR to add the bindings here

Currently the RivePlayer class in this repo directly inherits from SKCanvasView instead of just defining an API with bindable properties and methods, and putting the logic in handlers (as described in https://learn.microsoft.com/en-us/dotnet/maui/user-interface/handlers/create?view=net-maui-8.0).

If you want to have these two codebases merged, then there needs to be

From a technical point I'm wondering what approach would have a better performance and smaller filesize - directly embedding the compiled C library, or binding the Android / iOS libraries with their own references? However, I think the Flutter library also builds upon the Android / iOS libraries instead of building its own from the C-code.

I tried compiling the C library, and as an outsider not used to the C ecosystem and that premake5 build system I found it a huge barrier :-/

matmork commented 5 months ago

Seeing the two approaches are so different I agree it's best to keep them separate. Performance and file size is probably better by embedding. Flutter is built upon skia/impeller so maybe they are hooking into that but I see the rive-react-native is also just wrapping the native runtimes