jbowmanp1107 / ImageCropper.Maui

MIT License
43 stars 10 forks source link

Error on iOS #13

Closed juliusdeblaaij closed 5 months ago

juliusdeblaaij commented 7 months ago

The following error occured, I have set the proper AppDelegate code from the Demo.

Loaded assembly: /private/var/containers/Bundle/Application/D999CFE2-0A8F-4494-A351-3C2759795DEC/PrismMauiBlank.app/System.Text.Encoding.dll [External]
Loaded assembly: /private/var/containers/Bundle/Application/D999CFE2-0A8F-4494-A351-3C2759795DEC/PrismMauiBlank.app/System.IO.dll [External]
Loaded assembly: /private/var/containers/Bundle/Application/D999CFE2-0A8F-4494-A351-3C2759795DEC/PrismMauiBlank.app/System.Runtime.Extensions.dll [External]
[0:] An error occurred: 'Could not create an native instance of the type 'Bind_TOCropViewController.TOCropViewController': the native class hasn't been loaded.
It is possible to ignore this condition by setting ObjCRuntime.Class.ThrowOnInitFailure to false.'. Callstack: '   at Foundation.NSObject.InitializeObject(Boolean alloced)
   at Foundation.NSObject..ctor(NSObjectFlag x)
   at UIKit.UIResponder..ctor(NSObjectFlag t)
   at UIKit.UIViewController..ctor(NSObjectFlag t)
   at Bind_TOCropViewController.TOCropViewController..ctor(UIImage image)
   at ImageCropper.Maui.PlatformImageCropper.ShowFromFile(ImageCropper imageCropper, String imageFile)
   at ImageCropper.Maui.ImageCropper.Show(Page page, String imageFile)
   at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_0(Object state)
   at Foundation.NSAsyncSynchronizationContextDispatcher.Apply()
   at UIKit.UIApplication.UIApplicationMain(Int32 argc, String[] argv, IntPtr principalClassName, IntPtr delegateClassName)
   at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass)
   at PrismMauiBlank.Program.Main(String[] args) in C:\Users\juliu\Documents\repos\WWR\PickCounterPrism\src\PrismMauiBlank\PrismMauiBlank\Platforms\iOS\Program.cs:line 13
   at System.Reflection.MethodInvoker.InterpretedInvoke(Object obj, Span`1 args, BindingFlags invokeAttr)'
The app has been terminated.
riaanswart commented 5 months ago

Anyone that can help with this? I have the same issue in my application. Disabling the throw on init feature will give a new error tat the TOCropViewController is being disposed.

juliusdeblaaij commented 5 months ago

@riaanswart I have found a solution that worked for me:

Based on mattjohnsonpint's post on the MAUI github:

"The _UnpackHotRestartFrameworkAssemblies target is assuming that framework files will be found as embedded resources in assemblies. When brought in via NuGet packages, they're not. They're either in a folder or zip file within the NuGet package itself.

I created a target that works around this problem. Put it in the .csproj of the app that's being built with Hot Restart and everything should work. I tested with nugets having either regular framework or xcframework.

https://gist.github.com/mattjohnsonpint/37d3ac06a563c41618fc933bf7282d66"

Adding the following code within the <project> tags of the relevant CS project fixes the issue.

<!-- 
  This target ensures that iOS Frameworks and XCFrameworks are collected from NuGet packages when using Hot Restart.
  _UnpackHotRestartFrameworkAssemblies doesn't work for NuGet packages, because the frameworks aren't stored as embedded resources, but just files in the package. 
-->
<Target Name="_CollectHotRestartFrameworksFromPackages" BeforeTargets="_CollectHotRestartFrameworks" Condition="'$(IsHotRestartBuild)' == 'true'">

  <!-- 
    Find all resources within NuGet packages.
    For example, a package with assembly Foo.dll will have an adjacent Foo.resources folder or a Foo.resources.zip file.
  -->
  <ItemGroup>
    <_PackageResourcesDirs Include="@(AssembliesWithFrameworks -> '%(RootDir)%(Directory)%(FileName).resources')"
                           Condition="Exists('%(RootDir)%(Directory)%(FileName).resources')" />

    <_PackageResourcesZips Include="@(AssembliesWithFrameworks -> '%(RootDir)%(Directory)%(FileName).resources.zip')"
                           Condition="Exists('%(RootDir)%(Directory)%(FileName).resources.zip')" />
  </ItemGroup>

  <!-- 
    For zipped resources, we'll need to unpack them somewhere.
    The DeviceSpecificIntermediateOutputPath can get too long and hit max path, so we'll work from TEMP instead.
  -->
  <PropertyGroup>
    <HotRestartPackageResourcesDir>$(TEMP)\Xamarin\HotRestart\Resources\</HotRestartPackageResourcesDir>
  </PropertyGroup>
  <Unzip ZipFilePath="@(_PackageResourcesZips)"
         ExtractionPath="$(HotRestartPackageResourcesDir)%(NuGetPackageId)\%(NuGetPackageVersion)"
         Condition="'@(_PackageResourcesZips)' != '' And !Exists('$(HotRestartPackageResourcesDir)%(NuGetPackageId)\%(NuGetPackageVersion)')" />

  <!-- Add the folders where we unzipped each file to _PackageResourcesDirs -->
  <ItemGroup Condition="'@(_PackageResourcesZips)' != ''">
    <_PackageResourcesDirs Include="@(_PackageResourcesZips -> '$(HotRestartPackageResourcesDir)%(NuGetPackageId)\%(NuGetPackageVersion)')" />
  </ItemGroup>

  <!-- If we have any _PackageResourcesDirs (from either originally zipped or unzipped), scan them for frameworks. -->
  <ItemGroup Condition="'@(_PackageResourcesDirs)' != ''">

    <!-- Regular frameworks will be found immediately in the root of the resources folder.  -->
    <_PackageResourcesFrameworkFiles Include="%(_PackageResourcesDirs.Identity)\*.framework\*" />

    <!-- XCFrameworks will have multiple targets.  We need only the framework from the ios-arm64 target.  -->
    <_PackageResourcesFrameworkFiles Include="%(_PackageResourcesDirs.Identity)\**\*.xcframework\ios-arm64\*.framework\*" />

    <!-- Condense the file list to the exact list of frameworks we're adding. -->
    <_HotRestartFrameworksFromPackages Include="@(_PackageResourcesFrameworkFiles -> '%(RootDir)%(Directory)')" KeepDuplicates="false" />

    <!-- Finally, add them to _HotRestartFrameworks, which is used by the existing _CollectHotRestartFrameworks target. -->
    <_HotRestartFrameworks Include="@(_HotRestartFrameworksFromPackages -> TrimEnd('\'))" />

  </ItemGroup>

</Target>

If this workaround fixes the problem for you too, I will be confident it is a good enough fix to consider the issue closed. So please try this and let me know!

riaanswart commented 5 months ago

@juliusdeblaaij thank you, adding it to the cs proj file worked to not get the exception anymore.
However after taking a photo or selecting a photo, the crop view did not show. To fix this I took the implementation of IImageCropperWrapper into my app and replaced UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(cropViewController, true, null); with UIApplication.SharedApplication.Windows.Last().RootViewController.PresentViewController(cropViewController, true, null); to get it working. Appreciate the help

juliusdeblaaij commented 5 months ago

Thanks for the additional info, I will close this issue as the solution is found and verified. Others can know fix the follow up problem with your code. ~ Julius