Open nielsdelporte opened 3 years ago
I had the same problem.
After some digging, the problem is that the code generated by the @Parcelize
changed a bit, now it uses generics, and it seems that Xamarin doesn't work with the new implementation.
To fix this, I added the following code to the Metadata.xml.
<attr path="/api/package[@name='com.project.example.parcelize.enums']/class[@name='Info.Creator']/method[@name='createFromParcel']" name="managedReturn">Java.Lang.Object</attr>
<attr path="/api/package[@name='com.project.example.parcelize.enums']/class[@name='Info.Creator']/method[@name='newArray']" name="managedReturn">Java.Lang.Object[]</attr>
<attr path="/api/package[@name='com.project.example.parcelize.enums']/class[@name='Delete.Creator']/method[@name='createFromParcel']" name="managedReturn">Java.Lang.Object </attr>
<attr path="/api/package[@name='com.project.example.parcelize.enums']/class[@name='Delete.Creator']/method[@name='newArray']" name="managedReturn">Java.Lang.Object[]</attr>
You need to add this to every class that uses @Parcelize
.
Thanks for the tip, @4brunu! Unfortunately, that looks exactly like what we added to the metadata.xml as well (at first with the sealed typename included in class@name), but we still get mismatch error messages. Did you need to do any other things? Add an extra nuget package or resetting cache?
<attr path="/api/package[@name='com.project.example.parcelize.enums']/class[@name='Info.CREATOR']/method[@name='createFromParcel']" name="managedReturn">Java.Lang.Object</attr>
<attr path="/api/package[@name='com.project.example.parcelize.enums']/class[@name='Info.CREATOR']/method[@name='newArray' and count(parameter)=1 and parameter[1][@type='int']]" name="managedReturn">Java.Lang.Object[]</attr>
<attr path="/api/package[@name='com.project.example.parcelize.enums']/class[@name='Delete.CREATOR']/method[@name='createFromParcel']" name="managedReturn">Java.Lang.Object</attr>
<attr path="/api/package[@name='com.project.example.parcelize.enums']/class[@name='Delete.CREATOR']/method[@name='newArray' and count(parameter)=1 and parameter[1][@type='int']]" name="managedReturn">Java.Lang.Object[]</attr>
/Repositories/parcelize_example/ParcelizeExample.Bindings/obj/Debug/generated/src/Com.Project.Example.Parcelize.Enums.Options.cs(68,68): Error CS0738: 'Options.Info.Creator' does not implement interface member 'IParcelableCreator.CreateFromParcel(Parcel)'. 'Options.Info.Creator.CreateFromParcel(Parcel)' cannot implement 'IParcelableCreator.CreateFromParcel(Parcel)' because it does not have the matching return type of 'Object'. (CS0738) (ParcelizeExample.Bindings) /Repositories/parcelize_example/ParcelizeExample.Bindings/obj/Debug/generated/src/Com.Project.Example.Parcelize.Enums.Options.cs(68,68): Error CS0738: 'Options.Info.Creator' does not implement interface member 'IParcelableCreator.NewArray(int)'. 'Options.Info.Creator.NewArray(int)' cannot implement 'IParcelableCreator.NewArray(int)' because it does not have the matching return type of 'Object[]'. (CS0738) (ParcelizeExample.Bindings)
It was just this on the Metadata.xml
The problem here may be with the sealed class.
Try the following.
<attr path="/api/package[@name='com.project.example.parcelize.enums']/class[@name='Options.Info.Creator']/method[@name='createFromParcel']" name="managedReturn">Java.Lang.Object</attr>
<attr path="/api/package[@name='com.project.example.parcelize.enums']/class[@name='Options.Info.Creator']/method[@name='newArray']" name="managedReturn">Java.Lang.Object[]</attr>
<attr path="/api/package[@name='com.project.example.parcelize.enums']/class[@name='Options.Delete.Creator']/method[@name='createFromParcel']" name="managedReturn">Java.Lang.Object</attr>
<attr path="/api/package[@name='com.project.example.parcelize.enums']/class[@name='Options.Delete.Creator']/method[@name='newArray']" name="managedReturn">Java.Lang.Object[]</attr>
That doesn't work either; it's something we tried initially as well. We're using this approach for plain Kotlin object classes, and that works for us. Does it have anything to do with the way the sealed class is written, maybe?
This is the compiled code
package com.project.example.parcelize.enums;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.DrawableRes;
import androidx.annotation.IdRes;
import androidx.annotation.StringRes;
import kotlin.Metadata;
import kotlin.jvm.internal.DefaultConstructorMarker;
import kotlin.jvm.internal.Intrinsics;
import kotlinx.parcelize.Parcelize;
import org.jetbrains.annotations.NotNull;
@Metadata(bv = {1, 0, 3}, d1 = {"\u0000\u001a\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\u0010\b\n\u0002\b\f\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0000\b6\u0018\u00002\u00020\u0001:\u0002\r\u000eB'\b\u0002\u0012\b\b\u0001\u0010\u0007\u001a\u00020\u0002\u0012\b\b\u0001\u0010\t\u001a\u00020\u0002\u0012\b\b\u0001\u0010\u0003\u001a\u00020\u0002¢\u0006\u0004\b\u000b\u0010\fR\u0019\u0010\u0003\u001a\u00020\u00028\u0006@\u0006¢\u0006\f\n\u0004\b\u0003\u0010\u0004\u001a\u0004\b\u0005\u0010\u0006R\u0019\u0010\u0007\u001a\u00020\u00028\u0006@\u0006¢\u0006\f\n\u0004\b\u0007\u0010\u0004\u001a\u0004\b\b\u0010\u0006R\u0019\u0010\t\u001a\u00020\u00028\u0006@\u0006¢\u0006\f\n\u0004\b\t\u0010\u0004\u001a\u0004\b\n\u0010\u0006\u0001\u0002\u000f\u0010¨\u0006\u0011"}, d2 = {"Lcom/project/example/parcelize/enums/Options;", "Landroid/os/Parcelable;", "", "viewId", "I", "getViewId", "()I", "iconResId", "getIconResId", "titleResId", "getTitleResId", "<init>", "(III)V", "Delete", "Info", "Lcom/project/example/parcelize/enums/Options$Info;", "Lcom/project/example/parcelize/enums/Options$Delete;", "teleconsultationandroid_release"}, k = 1, mv = {1, 4, 1})
/* compiled from: Options.kt */
public abstract class Options implements Parcelable {
private final int iconResId;
private final int titleResId;
private final int viewId;
@Parcelize
@Metadata(bv = {1, 0, 3}, d1 = {"\u0000 \n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\u0010\b\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0002\b\u0005\b\u0007\u0018\u00002\u00020\u0001B\u0007¢\u0006\u0004\b\u000b\u0010\fJ\u0010\u0010\u0003\u001a\u00020\u0002HÖ\u0001¢\u0006\u0004\b\u0003\u0010\u0004J \u0010\t\u001a\u00020\b2\u0006\u0010\u0006\u001a\u00020\u00052\u0006\u0010\u0007\u001a\u00020\u0002HÖ\u0001¢\u0006\u0004\b\t\u0010\n¨\u0006\r"}, d2 = {"Lcom/project/example/parcelize/enums/Options$Delete;", "Lcom/project/example/parcelize/enums/Options;", "", "describeContents", "()I", "Landroid/os/Parcel;", "parcel", "flags", "", "writeToParcel", "(Landroid/os/Parcel;I)V", "<init>", "()V", "teleconsultationandroid_release"}, k = 1, mv = {1, 4, 1})
/* compiled from: Options.kt */
public static final class Delete extends Options {
public static final Parcelable.Creator<Delete> CREATOR = new Creator();
@Metadata(bv = {1, 0, 3}, d1 = {}, d2 = {}, k = 3, mv = {1, 4, 1})
public static class Creator implements Parcelable.Creator<Delete> {
@Override // android.os.Parcelable.Creator
@NotNull
public final Delete createFromParcel(@NotNull Parcel parcel) {
Intrinsics.checkNotNullParameter(parcel, "in");
if (parcel.readInt() != 0) {
return new Delete();
}
return null;
}
@Override // android.os.Parcelable.Creator
@NotNull
public final Delete[] newArray(int i) {
return new Delete[i];
}
}
public Delete() {
super(R.drawable.background_icon, R.string.msg_xpto, R.id.card_view, null);
}
public int describeContents() {
return 0;
}
public void writeToParcel(@NotNull Parcel parcel, int i) {
Intrinsics.checkNotNullParameter(parcel, "parcel");
parcel.writeInt(1);
}
}
@Parcelize
@Metadata(bv = {1, 0, 3}, d1 = {"\u0000 \n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\u0010\b\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0002\b\u0005\b\u0007\u0018\u00002\u00020\u0001B\u0007¢\u0006\u0004\b\u000b\u0010\fJ\u0010\u0010\u0003\u001a\u00020\u0002HÖ\u0001¢\u0006\u0004\b\u0003\u0010\u0004J \u0010\t\u001a\u00020\b2\u0006\u0010\u0006\u001a\u00020\u00052\u0006\u0010\u0007\u001a\u00020\u0002HÖ\u0001¢\u0006\u0004\b\t\u0010\n¨\u0006\r"}, d2 = {"Lcom/project/example/parcelize/enums/Options$Info;", "Lcom/project/example/parcelize/enums/Options;", "", "describeContents", "()I", "Landroid/os/Parcel;", "parcel", "flags", "", "writeToParcel", "(Landroid/os/Parcel;I)V", "<init>", "()V", "teleconsultationandroid_release"}, k = 1, mv = {1, 4, 1})
/* compiled from: Options.kt */
public static final class Info extends Options {
public static final Parcelable.Creator<Info> CREATOR = new Creator();
@Metadata(bv = {1, 0, 3}, d1 = {}, d2 = {}, k = 3, mv = {1, 4, 1})
public static class Creator implements Parcelable.Creator<Info> {
@Override // android.os.Parcelable.Creator
@NotNull
public final Info createFromParcel(@NotNull Parcel parcel) {
Intrinsics.checkNotNullParameter(parcel, "in");
if (parcel.readInt() != 0) {
return new Info();
}
return null;
}
@Override // android.os.Parcelable.Creator
@NotNull
public final Info[] newArray(int i) {
return new Info[i];
}
}
public Info() {
super(R.drawable.background_icon, R.string.msg_xpto, R.id.card_view, null);
}
public int describeContents() {
return 0;
}
public void writeToParcel(@NotNull Parcel parcel, int i) {
Intrinsics.checkNotNullParameter(parcel, "parcel");
parcel.writeInt(1);
}
}
private Options(@DrawableRes int i, @StringRes int i2, @IdRes int i3) {
this.iconResId = i;
this.titleResId = i2;
this.viewId = i3;
}
public final int getIconResId() {
return this.iconResId;
}
public final int getTitleResId() {
return this.titleResId;
}
public final int getViewId() {
return this.viewId;
}
public /* synthetic */ Options(int i, int i2, int i3, DefaultConstructorMarker defaultConstructorMarker) {
this(i, i2, i3);
}
}
The change in kotlin 1.4.20 that was causing this issue, was this
public final Object createFromParcel(@NotNull Parcel parcel) {
...
}
...
public final Object[] newArray(int i) {
...
}
Turned in this
public final Info createFromParcel(@NotNull Parcel parcel) {
...
}
...
public final Info[] newArray(int i) {
...
}
And apparently xamarin don't deal very well with generics.
So, in theory, the solution would be
<attr path="/api/package[@name='com.project.example.parcelize.enums']/class[@name='Options.Info.Creator']/method[@name='createFromParcel']" name="managedReturn">Java.Lang.Object</attr>
<attr path="/api/package[@name='com.project.example.parcelize.enums']/class[@name='Options.Info.Creator']/method[@name='newArray']" name="managedReturn">Java.Lang.Object[]</attr>
<attr path="/api/package[@name='com.project.example.parcelize.enums']/class[@name='Options.Delete.Creator']/method[@name='createFromParcel']" name="managedReturn">Java.Lang.Object</attr>
<attr path="/api/package[@name='com.project.example.parcelize.enums']/class[@name='Options.Delete.Creator']/method[@name='newArray']" name="managedReturn">Java.Lang.Object[]</attr>
This was how I came up with the solution to my problem.
Context Android developers used to have the
@Parcelize
annotation to remove boilerplate implementation forParcelable
objects. The old plugin was deprecated in the 1.4.20 release of Kotlin, and if the native library still wants to use this feature, they now need to use the kotlin-parcelize plugin instead of the kotlin-android-extensions plugin.Problem A bindings project which updates the Xamarin.Kotlin.StdLib NuGet package will no longer compile if a native library is using the
@Parcelize
annotation.Steps to reproduce
sealed class
in the library which the Xamarin.Android solution should be able to access.import android.os.Parcelable import androidx.annotation.DrawableRes import androidx.annotation.IdRes import androidx.annotation.StringRes import kotlinx.parcelize.Parcelize import com.project.example.parcelize.R
/**
List of options. */ sealed class Options(@param:DrawableRes val iconResId: Int, @param:StringRes val titleResId: Int, @param:IdRes val viewId: Int) : Parcelable {
@Parcelize class Info : Options(R.drawable.ic_option_info, R.string.option_info, R.id.option_info)
@Parcelize class Delete : Options(R.drawable.ic_option_delete, R.string.option_delete, R.id.option_delete) }
Compile errors
Attempted solutions
Environment
=== Visual Studio Community 2019 for Mac ===
Version 8.7.4 (build 38) Installation UUID: 0e4b3431-41c6-4d2a-a600-8ef884d57a59 GTK+ 2.24.23 (Raleigh theme) Xamarin.Mac 6.18.0.23 (d16-6 / 088c73638)
=== Mono Framework MDK ===
Runtime: Mono 6.12.0.90 (2020-02/d3daacdaa80) (64-bit) Package version: 612000090
=== Roslyn (Language Service) ===
3.7.0-6.20412.3+d3c3a44a4e7ad31cc75c59be0d3df4a19ff33878
=== NuGet ===
Version: 5.7.0.6702
=== .NET Core SDK ===
SDK: /usr/local/share/dotnet/sdk/3.1.401/Sdks SDK Versions: 3.1.401 3.1.301 3.1.300 3.1.200 3.1.100 2.1.505 MSBuild SDKs: /Library/Frameworks/Mono.framework/Versions/6.12.0/lib/mono/msbuild/Current/bin/Sdks
=== .NET Core Runtime ===
Runtime: /usr/local/share/dotnet/dotnet Runtime Versions: 3.1.7 3.1.5 3.1.4 3.1.2 3.1.0 2.1.21 2.1.19 2.1.18 2.1.16 2.1.14 2.1.9
=== Xamarin.Profiler ===
Version: 1.6.12.29 Location: /Applications/Xamarin Profiler.app/Contents/MacOS/Xamarin Profiler
=== Updater ===
Version: 11
=== Apple Developer Tools ===
A valid Xcode installation was not found at the configured location: '/Applications/Xcode.app'
=== Xamarin.Mac ===
Xamarin.Mac not installed. Can't find /Library/Frameworks/Xamarin.Mac.framework/Versions/Current/Version.
=== Xamarin.iOS ===
Version: 13.20.2.2 (Visual Studio Community) Hash: 817b6f72a Branch: d16-7 Build date: 2020-07-18 18:45:00-0400
=== Xamarin Designer ===
Version: 16.7.0.492 Hash: f5afe667d Branch: remotes/origin/d16-7-vsmac Build date: 2020-07-10 18:42:54 UTC
=== Xamarin.Android ===
Version: 10.3.1.4 (Visual Studio Community) Commit: xamarin-android/d16-6/3a10de9 Android SDK: /Users/nielsdelporte/Library/Developer/Xamarin/android-sdk-macosx Supported Android versions: None installed
SDK Tools Version: 26.1.1 SDK Platform Tools Version: 30.0.5 SDK Build Tools Version: 30.0.3
Build Information: Mono: 165f4b0 Java.Interop: xamarin/java.interop/d16-6@2cab35c ProGuard: xamarin/proguard/master@905836d SQLite: xamarin/sqlite/3.31.1@49232bc Xamarin.Android Tools: xamarin/xamarin-android-tools/d16-6@bfb66f3
=== Microsoft OpenJDK for Mobile ===
Java SDK: /Users/nielsdelporte/Library/Developer/Xamarin/jdk/microsoft_dist_openjdk_1.8.0.25 1.8.0-25 Android Designer EPL code available here: https://github.com/xamarin/AndroidDesigner.EPL
=== Android SDK Manager ===
Version: 16.7.0.13 Hash: 8380518 Branch: remotes/origin/d16-7~2 Build date: 2020-08-19 22:18:28 UTC
=== Android Device Manager ===
Version: 16.7.0.24 Hash: bb090a3 Branch: remotes/origin/d16-7 Build date: 2020-08-19 22:18:52 UTC
=== Build Information ===
Release ID: 807040038 Git revision: 7f322926a2e0a5fa0c1e3833215a191883f7514a Build date: 2020-08-20 10:10:20-04 Build branch: release-8.7 Xamarin extensions: 7f322926a2e0a5fa0c1e3833215a191883f7514a
=== Operating System ===
Mac OS X 10.15.7 Darwin 19.6.0 Darwin Kernel Version 19.6.0 Tue Jan 12 22:13:05 PST 2021 root:xnu-6153.141.16~1/RELEASE_X86_64 x86_64