Picture above represents the results of 3 sleepless nights. No, I didn’t rewrite the Android framework. I generated a bunch of proxy classes to access them from Mono though. Rough idea of how it works:
- Java application reflects through Android framework SDK jar and outputs an XML file that represents the object model.
- C# application generates thousands of code files of said object model. (This is similar to jni4net, but that doesn’t work on anything but Windows).
- Tag all the methods with the [MethodImpl(MethodImplOptions.InternalCall)] attribute.
- Implement the method calls at runtime with a combination of dynamically created expression tree delegates and mono_add_internal_call.
The class contents actually have no code, so the total dll size is pretty small (800k). Here’s what the LinearLayout “implementation” looks like:
namespace android.widget { public class LinearLayout : android.view.ViewGroup { public class LayoutParams : android.view.ViewGroup.MarginLayoutParams { [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public virtual extern java.lang.String debug(java.lang.String arg0); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public extern LayoutParams(android.content.Context arg0, android.util.AttributeSet arg1); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public extern LayoutParams(int arg0, int arg1); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public extern LayoutParams(int arg0, int arg1, float arg2); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public extern LayoutParams(android.view.ViewGroup.LayoutParams arg0); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public extern LayoutParams(android.view.ViewGroup.MarginLayoutParams arg0); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] internal extern LayoutParams(); } [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public virtual extern void setGravity(int arg0); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] protected override extern void onLayout(bool arg0, int arg1, int arg2, int arg3, int arg4); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public override extern int getBaseline(); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] protected override extern void onMeasure(int arg0, int arg1); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] protected override extern bool checkLayoutParams(android.view.ViewGroup.LayoutParams arg0); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public virtual extern new android.widget.LinearLayout.LayoutParams generateLayoutParams(android.util.AttributeSet arg0); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] protected virtual extern new android.widget.LinearLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams arg0); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] protected virtual extern new android.widget.LinearLayout.LayoutParams generateDefaultLayoutParams(); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public virtual extern bool isBaselineAligned(); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public virtual extern void setBaselineAligned(bool arg0); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public virtual extern int getBaselineAlignedChildIndex(); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public virtual extern void setBaselineAlignedChildIndex(int arg0); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public virtual extern float getWeightSum(); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public virtual extern void setWeightSum(float arg0); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public virtual extern void setOrientation(int arg0); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public virtual extern int getOrientation(); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public virtual extern void setHorizontalGravity(int arg0); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public virtual extern void setVerticalGravity(int arg0); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public extern LinearLayout(android.content.Context arg0, android.util.AttributeSet arg1); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] public extern LinearLayout(android.content.Context arg0); [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.InternalCall)] internal extern LinearLayout(); } }
A year of on and off hacking coming to fruition soon…