Skip to content

Commit 4015a41

Browse files
committed
Sample [to remove after moving into a unit test]
Use `@(AndroidJavaSource)` to add a pair of Java types: public class RemapActivity extends Activity { public void onMyCreate (android.os.Bundle bundle); } class ViewHelper { public static void mySetOnClickListener (android.view.View view, android.view.View.OnClickListener listener); } Update `remap.xml` to: 1. Rename `android.app.Activity` to `example.RemapActivity` 2. Rename "`Activity.onCreate()`" to `RemapActivity.onMyCreate()` 3. "Patch" `View.setOnClickListener()` to instead call `ViewHelper.mySetOnClickListener()`. "Learnings" from this exercise: 1. Changing the Java hierarchy "requires" changing the managed hierarchy to mirror it. If we rename `Activity` to `RemapActivity` but *don't* change `MainActivity` to inherit the (bound!) `Example.RemapActivity`, the app *crashes*: JNI DETECTED ERROR IN APPLICATION: can't call void example.RemapActivity.onMyCreate(android.os.Bundle) on instance of example.MainActivity This can be "fixed" *without* changing the base class of `MainActivity` by instead changing the base class of the Java Callable Wrapper for `MainActivity` to `example.RemapActivity`. This can be done manually, but isn't really supported in "normal" xamarin-android usage. Presumably InTune would make this Just Work by e.g. patching the `MainActivity.class` file. 2. Note the "scare quotes" in (2): you *don't* rename `Activity.onCreate()`, because after renaming `Activity` to `example.RemapActivity`, `Activity` *no longer exists*. This warps the brain a bit. You can rename methods, but the `/replace-method/@source-type` value needs to be the `/replace-type/@to` value. This: <replace-method source-type="example/RemapActivity" source-method-name="onCreate" target-type="example/RemapActivity" target-method-name="onMyCreate" target-method-instance-to-static="false" /> not this: <replace-method source-type="android/app/Activity" source-method-name="onCreate" target-type="example/RemapActivity" target-method-name="onMyCreate" target-method-instance-to-static="false" /> While it would be more intuitive to support the latter, I couldn't figure out how to make it work robustly and efficiently. 3. Don't intermix type renames with `/replace-method]@target-method-instance-to-static='true']`. It *can* be done, but also warps the brain. The deal with `@target-method-instance-to-static` is that it it changes the target method signature -- unless explicitly provided in `/replace-method/@target-method-signature` -- so that the "source declaring type" is a prefix. Thus given <replace-method source-type="android/view/View" source-method-name="setOnClickListener" target-type="example/ViewHelper" target-method-name="mySetOnClickListener" target-method-instance-to-static="true" /> we'll look for `ViewHelper.mySetOnClickListener(View, View.OnClickListener)`. If we renamed `View` to `MyView`, we would instead look for `ViewHelper.mySetOnClickListener(MyView, View.OnClickListener)` (note changed parameter type). This almost certainly *won't* work right for many circumstances.
1 parent d974391 commit 4015a41

File tree

8 files changed

+61
-21
lines changed

8 files changed

+61
-21
lines changed

samples/HelloWorld/HelloWorld/MainActivity.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@ namespace HelloWorld
99
Label = "HelloWorld",
1010
MainLauncher = true,
1111
Name = "example.MainActivity")]
12-
public class MainActivity : Activity
12+
public class MainActivity :
13+
#if NET
14+
Example.RemapActivity
15+
#else // NET
16+
Activity
17+
#endif // NET
1318
{
1419
int count = 1;
1520

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package example;
2+
3+
import android.util.Log;
4+
5+
public class RemapActivity extends android.app.Activity {
6+
public void onMyCreate (android.os.Bundle bundle) {
7+
Log.d ("*jonp*", "RemapActivity.onMyCreate() invoked!");
8+
super.onCreate(bundle);
9+
}
10+
}
11+
12+
class ViewHelper {
13+
public static void mySetOnClickListener (android.view.View view, android.view.View.OnClickListener listener) {
14+
Log.d ("*jonp*", "ViewHelper.mySetOnClickListener() invoked!");
15+
view.setOnClickListener (listener);
16+
}
17+
}
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
11
<replacements>
2-
<replace-type from="android/app/Activity" to="android/app/ListActivity" />
2+
<replace-type from="android/app/Activity" to="example/RemapActivity" />
3+
<replace-method
4+
source-type="example/RemapActivity"
5+
source-method-name="onCreate"
6+
target-type="example/RemapActivity"
7+
target-method-name="onMyCreate" target-method-instance-to-static="false" />
8+
<replace-method
9+
source-type="android/view/View"
10+
source-method-name="setOnClickListener"
11+
target-type="example/ViewHelper"
12+
target-method-name="mySetOnClickListener" target-method-instance-to-static="true" />
313
</replacements>

src/Mono.Android/Android.Runtime/AndroidRuntime.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -341,16 +341,25 @@ protected override IEnumerable<string> GetSimpleReferences (Type type)
341341

342342
Logger.Log (LogLevel.Warn, "*jonp*", $"# jonp: targetType={targetType.ToString ()}, targetName={targetName.ToString ()}, targetSig=`{targetSig.ToString()}`, paramCount={paramCountStr.ToString ()}, isStatic={isStaticStr.ToString ()}");
343343

344-
int paramCount = 0;
345-
if (!paramCountStr.IsEmpty &&
346-
!int.TryParse (paramCountStr, 0, System.Globalization.CultureInfo.InvariantCulture, out paramCount)) {
347-
return null;
344+
int? paramCount = null;
345+
if (!paramCountStr.IsEmpty) {
346+
if (!int.TryParse (paramCountStr, 0, System.Globalization.CultureInfo.InvariantCulture, out var count)) {
347+
return null;
348+
}
349+
paramCount = count;
348350
}
351+
349352
bool isStatic = false;
350353
if (isStaticStr.Equals ("true", StringComparison.Ordinal)) {
351354
isStatic = true;
352355
}
353356

357+
if (targetSig.IsEmpty && isStatic) {
358+
paramCount = paramCount ?? JniMemberSignature.GetParameterCountFromMethodSignature (jniMethodSignature);
359+
paramCount++;
360+
jniMethodSignature = $"(L{jniSourceType};" + jniMethodSignature.Substring ("(".Length);
361+
}
362+
354363
return new JniRuntime.ReplacementMethodInfo {
355364
SourceJniType = jniSourceType,
356365
SourceJniMethodName = jniMethodName,

src/Mono.Android/Android.Runtime/JNIEnv.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ internal static unsafe void Initialize (JnienvInitializeArgs* args)
182182
if (args->mappingXml != IntPtr.Zero) {
183183
var xml = Encoding.UTF8.GetString ((byte*) args->mappingXml, args->mappingXmlLen);
184184
Logger.Log (LogLevel.Warn, "*jonp*", $"# jonp: mapping xml: len={args->mappingXmlLen}; {xml}");
185-
(ReplacementTypes, ReplacementMethods) = MamXmlParser.Parse (xml);
185+
(ReplacementTypes, ReplacementMethods) = MamXmlParser.ParseStrings (xml);
186186
}
187187
#endif // NET
188188

src/monodroid/jni/mono_android_Runtime.h

Lines changed: 8 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/monodroid/jni/monodroid-glue.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,7 +1192,7 @@ MonodroidRuntime::init_android_runtime (
11921192
native_to_managed_index = internal_timing->start_event (TimingEventKind::NativeToManagedTransition);
11931193
}
11941194

1195-
if (mappingXml != nullptr) {
1195+
if (mappingXml != nullptr && mappingXmlLen > 0) {
11961196
init.mappingXml = env->GetByteArrayElements (mappingXml, nullptr);
11971197
init.mappingXmlLen = mappingXmlLen;
11981198
}
@@ -2449,7 +2449,7 @@ JNI_OnLoad (JavaVM *vm, void *reserved)
24492449
JNIEXPORT void JNICALL
24502450
Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobjectArray runtimeApksJava,
24512451
jstring runtimeNativeLibDir, jobjectArray appDirs, jobject loader,
2452-
[[maybe_unused]] jobjectArray externalStorageDirs, jobjectArray assembliesJava, jbyteArray mappingXml, jint mappingXmlLen, [[maybe_unused]] jstring packageName,
2452+
[[maybe_unused]] jobjectArray externalStorageDirs, jobjectArray assembliesJava, [[maybe_unused]] jstring packageName,
24532453
jint apiLevel, [[maybe_unused]] jobjectArray environmentVariables)
24542454
{
24552455
monodroidRuntime.Java_mono_android_Runtime_initInternal (
@@ -2461,8 +2461,8 @@ Java_mono_android_Runtime_init (JNIEnv *env, jclass klass, jstring lang, jobject
24612461
appDirs,
24622462
loader,
24632463
assembliesJava,
2464-
mappingXml,
2465-
mappingXmlLen,
2464+
/* mappingXml */ nullptr,
2465+
/* mappingXmlLen */ 0,
24662466
apiLevel,
24672467
/* isEmulator */ JNI_FALSE,
24682468
/* haveSplitApks */ JNI_FALSE

0 commit comments

Comments
 (0)