Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Android Callable Wrappers (ACWs) are required whenever the Android runtime invokes managed code. These wrappers are required because there is no way to register classes with ART (the Android runtime) at runtime. (Specifically, the JNI DefineClass() function is not supported by the Android runtime.} Android Callable Wrappers thus make up for the lack of runtime type registration support.
Every time Android code needs to execute a virtual or interface
method that is overridden or implemented in managed code,
Xamarin.Android must provide a Java proxy so that this method is
dispatched to the appropriate managed type. These Java proxy types are
Java code that has the "same" base class and Java interface list as
the managed type, implementing the same constructors and declaring any
overridden base class and interface methods.
Android callable wrappers are generated by the monodroid.exe program during the build process: they are generated for all types that (directly or indirectly) inherit Java.Lang.Object.
Android Callable Wrapper Naming
Package names for Android Callable Wrappers are based on the MD5SUM of the assembly-qualified name of the type being exported. This naming technique makes it possible for the same fully-qualified type name to be made available by different assemblies without introducing a packaging error.
Because of this MD5SUM naming scheme, you cannot directly access your
types by name. For example, the following adb command will not work
because the type name my.ActivityType is not generated by default:
adb shell am start -n My.Package.Name/my.ActivityType
Also, you may see errors like the following if you attempt to reference a type by name:
java.lang.ClassNotFoundException: Didn't find class "com.company.app.MainActivity"
on path: DexPathList[[zip file "/data/app/com.company.App-1.apk"] ...
If you do require access to types by name, you can declare a name for
that type in an attribute declaration. For example, here is code that
declares an activity with the fully-qualified name My.ActivityType:
namespace My {
[Activity]
public partial class ActivityType : Activity {
/* ... */
}
}
The ActivityAttribute.Name property can be set to explicitly declare
the name of this activity:
namespace My {
[Activity(Name="my.ActivityType")]
public partial class ActivityType : Activity {
/* ... */
}
}
After this property setting is added, my.ActivityType can be accessed
by name from external code and from adb scripts. The Name attribute
can be set for many different types including Activity,
Application, Service, BroadcastReceiver, and ContentProvider:
- ActivityAttribute.Name
- ApplicationAttribute.Name
- ServiceAttribute.Name
- BroadcastReceiverAttribute.Name
- ContentProviderAttribute.Name
MD5SUM-based ACW naming was introduced in Xamarin.Android 5.0. For more information about attribute naming, see RegisterAttribute.
Implementing Interfaces
There are times when you may need to implement an Android interface, such as
Android.Content.IComponentCallbacks.
Since all Android classes and interface extend the
Android.Runtime.IJavaObject
interface, the question arises: how do we implement IJavaObject?
The question was answered above: the reason all Android types need to
implement IJavaObject is so that Xamarin.Android has an Android
callable wrapper to provide to Android, i.e. a Java proxy for the given
type. Since monodroid.exe only looks for Java.Lang.Object
subclasses, and Java.Lang.Object implements IJavaObject, the answer
is obvious: subclass Java.Lang.Object:
class MyComponentCallbacks : Java.Lang.Object, Android.Content.IComponentCallbacks {
public void OnConfigurationChanged (Android.Content.Res.Configuration newConfig)
{
// implementation goes here...
}
public void OnLowMemory ()
{
// implementation goes here...
}
}
Implementation Details
The remainder of this page provides implementation details subject to change without notice (and is presented here only because developers will be curious about what's going on).
For example, given the following C# source:
using System;
using Android.App;
using Android.OS;
namespace Mono.Samples.HelloWorld
{
public class HelloAndroid : Activity
{
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
SetContentView (R.layout.main);
}
}
}
The mandroid.exe program will generate the following Android Callable Wrapper:
package mono.samples.helloWorld;
public class HelloAndroid
extends android.app.Activity
{
static final String __md_methods;
static {
__md_methods = "n_onCreate:(Landroid/os/Bundle;)V:GetOnCreate_Landroid_os_Bundle_Handler\n" + "";
mono.android.Runtime.register (
"Mono.Samples.HelloWorld.HelloAndroid, HelloWorld, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null", HelloAndroid.class, __md_methods);
}
public HelloAndroid ()
{
super ();
if (getClass () == HelloAndroid.class)
mono.android.TypeManager.Activate (
"Mono.Samples.HelloWorld.HelloAndroid, HelloWorld, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null", "", this, new java.lang.Object[] { });
}
@Override
public void onCreate (android.os.Bundle p0)
{
n_onCreate (p0);
}
private native void n_onCreate (android.os.Bundle p0);
}
Notice that the base class is preserved, and native method
declarations are provided for each method that is overridden within
managed code.