解決Xamarin.Android繫結第三方庫時型別丟失的問題

johnchou發表於2021-09-09

現象

今天在做一個第三方庫繫結時,遇到如下情況:

圖片描述

摘取其中一段程式碼如下:

/Users/huangboru/myfile/xamarin_workspace/version4/CrashEyeTestPlus/obj/Debug/generated/src/Com.Xsj.Crasheye.ActionError.cs(88,88): Error CS0234: The type or namespace name 'IInterfaceDataType' does not exist in the namespace 'Com.Xsj.Crasheye' (are you missing an assembly reference?) (CS0234) (CrashEyeTestPlus)

錯誤程式碼的意思是無法找到IInterfaceDataType型別。

解決過程

為了方便檢視繫結的情況,我新建了一個Android Studio專案,新增這個第三方庫,去看這個型別是什麼,看到的情況如下:

package com.xsj.crasheye;import android.content.Context;interface InterfaceDataType {    String toJsonLine();    void send(Context var1, NetSender var2, boolean var3);    void send(NetSender var1, boolean var2);    void save(BaseDataSaver var1);
}

查閱,發現此類問題的可能情況有:

圖片描述

圖片描述

透過分析,我認為這個問題是第4種情況:Java允許一個公開型別去繼承一個非公開的型別,而這在.Net中是不受支援的。由於繫結生成器無法生成對非公開型別的繫結,自然也就無法準確地繫結其公開的子類。為了解決這個問題,我們需要在Metadata.xml檔案中將這個非公開的型別宣告為公開型別。
在我的專案中,我新增的程式碼如下:

    <attr path="/api/package[@name='com.xsj.crasheye']/interface[@name='InterfaceDataType']" name="visibility">public</attr>
    <attr path="/api/package[@name='com.xsj.crasheye']/interface[@name='InterfaceExecutor']" name="visibility">public</attr>

不過問題並沒有完全消除,還有一個error:

/Users/huangboru/myfile/xamarin_workspace/version4/CrashEyeTestPlus/obj/Debug/generated/src/Com.Xsj.Crasheye.ActionTransactionStop.cs(38,38): Error CS0234: The type or namespace name 'EnumTransactionStatus' does not exist in the namespace 'Com.Xsj.Crasheye' (are you missing an assembly reference?) (CS0234) (CrashEyeTestPlus)

我跟進到出現問題的地方:

    // Metadata.xml XPath field reference: path="/api/package[@name='com.xsj.crasheye']/class[@name='ActionTransactionStop']/field[@name='status']"
        [Register ("status")]        protected global::Com.Xsj.Crasheye.EnumTransactionStatus Status {
            get {                const string __id = "status.Lcom/xsj/crasheye/EnumTransactionStatus;";                var __v = _members.InstanceFields.GetObjectValue (__id, this);                return global::Java.Lang.Object.GetObject<global::Com.Xsj.Crasheye.EnumTransactionStatus> (__v.Handle, JniHandleOwnership.TransferLocalRef);
            }
            set {                const string __id = "status.Lcom/xsj/crasheye/EnumTransactionStatus;";

                IntPtr native_value = global::Android.Runtime.JNIEnv.ToLocalJniHandle (value);                try {
                    _members.InstanceFields.SetValue (__id, this, new JniObjectReference (native_value));
                } finally {                    global::Android.Runtime.JNIEnv.DeleteLocalRef (native_value);
                }
            }
        }

對方是一個非公開enum型別,我嘗試像上面一樣公開這個enum,但不可行。

觀察程式碼可知,Xamarin在嘗試繫結一個ActionTransactionStop的status欄位,我到原生專案中檢視這個欄位:

public class ActionTransactionStop extends ActionTransaction implements InterfaceDataType {    protected EnumTransactionStatus status;
    .......
}

可知這是一個protected的欄位,我們應該用不著也不應該訪問這個欄位,於是我直接新增了移除這個欄位繫結的程式碼如下:

 <remove-node path="/api/package[@name='com.xsj.crasheye']/class[@name='ActionTransactionStop']/field[@name='status']" />

reBuild,ok!



作者:臨歲之寒
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4422/viewspace-2820963/,如需轉載,請註明出處,否則將追究法律責任。

相關文章