PackageName属性覆盖Xamarin中的错误

时间:2015-07-16 16:18:26

标签: android xamarin xamarin.android

[附件项目文件:http://forums.xamarin.com/discussion/45900/application-packagename-property-override-problem-is-this-xamarin-bug]

我试图覆盖Application PackageName属性。但是发生了java.lang.UnsatisfiedLinkError(未找到本机方法)。所以我在谷歌搜索这个问题,我发现一个完全相同问题的问题(https://forums.xamarin.com/discussion/45434/application-packagename-property-override-problem)。但遗憾的是没有答案。我该怎么办?

[Application]
public class TestApplication : Application
{
    public override string PackageName
    {
        get
        {
            return "com.fake.packagename";
        }
    }
}

错误日志

07-17 23:06:57.179 E/AndroidRuntime(25801): FATAL EXCEPTION: main
07-17 23:06:57.179 E/AndroidRuntime(25801): Process: TestApp.TestApp, PID: 25801
07-17 23:06:57.179 E/AndroidRuntime(25801): java.lang.UnsatisfiedLinkError: Native method not found: md5cf27010e14af20e69784a5a54418b85f.TestApplication.n_getPackageName:()Ljava/lang/String;
07-17 23:06:57.179 E/AndroidRuntime(25801): at md5cf27010e14af20e69784a5a54418b85f.TestApplication.n_getPackageName(Native Method)
07-17 23:06:57.179 E/AndroidRuntime(25801): at md5cf27010e14af20e69784a5a54418b85f.TestApplication.getPackageName(TestApplication.java:25)
07-17 23:06:57.179 E/AndroidRuntime(25801): at android.app.ActivityThread.installProvider(ActivityThread.java:4855)
07-17 23:06:57.179 E/AndroidRuntime(25801): at android.app.ActivityThread.installContentProviders(ActivityThread.java:4476)
07-17 23:06:57.179 E/AndroidRuntime(25801): at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4413)
07-17 23:06:57.179 E/AndroidRuntime(25801): at android.app.ActivityThread.access$1500(ActivityThread.java:142)
07-17 23:06:57.179 E/AndroidRuntime(25801): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1263)
07-17 23:06:57.179 E/AndroidRuntime(25801): at android.os.Handler.dispatchMessage(Handler.java:102)
07-17 23:06:57.179 E/AndroidRuntime(25801): at android.os.Looper.loop(Looper.java:136)
07-17 23:06:57.179 E/AndroidRuntime(25801): at android.app.ActivityThread.main(ActivityThread.java:5120)
07-17 23:06:57.179 E/AndroidRuntime(25801): at java.lang.reflect.Method.invokeNative(Native Method)
07-17 23:06:57.179 E/AndroidRuntime(25801): at java.lang.reflect.Method.invoke(Method.java:515)
07-17 23:06:57.179 E/AndroidRuntime(25801): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:792)
07-17 23:06:57.179 E/AndroidRuntime(25801): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608)
07-17 23:06:57.179 E/AndroidRuntime(25801): at dalvik.system.NativeStart.main(Native Method)

1 个答案:

答案 0 :(得分:1)

这看起来像MonoAndroid中的限制和错误;发生java.lang.UnsatisfiedLinkError异常是因为尚未向Mono运行时注册方法n_getPackageName并且无法解析。简短的回答是:

  • 由于MonoAndroids启动顺序的复杂性,可能无法覆盖PackageName的{​​{1}}属性。
  • 使用Xamarin提交错误报告。这是MonoAndroid启动例程中的一个错误(下面概述)。

兔子洞

让我们深入研究桥接Java代码,以确定发生这种情况的原因。构建MonoAndroid应用程序时,会在项目的Application目录中生成一堆Java代码。此源代码是互操作层,允许使用C#构建的应用程序通过Dalvik或ART在Android设备上执行。项目中的每个类都是Android组件([ProjectName]/obj/[Configuration]/android/srcApplicationServiceActivity等),会生成相应的.java源代码文件。

这是Fragment课程的一部分:

TestApp

这里要注意的重要事项是:

  • 链接到.NET程序集的重写方法的定义:

    package md5cf27010e14af20e69784a5a54418b85f;
    
    public class TestApplication
        extends mono.android.app.Application
        implements
            mono.android.IGCUserPeer
    {
        static final String __md_methods;
        static {
            __md_methods = 
                "n_getPackageName:()Ljava/lang/String;:GetGetPackageNameHandler\n" +
                "";
        }
    
        public TestApplication () throws java.lang.Throwable
        {
            super ();
        }
    
        public java.lang.String getPackageName ()
        {
            return n_getPackageName ();
        }
    
        private native java.lang.String n_getPackageName ();
    
        public void onCreate ()
        {
            mono.android.Runtime.register ("TestApp.TestApplication, TestApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", TestApplication.class, __md_methods);
            super.onCreate ();
        }
    
        java.util.ArrayList refList;
        public void monodroidAddReference (java.lang.Object obj)
        {
            if (refList == null)
                refList = new java.util.ArrayList ();
            refList.add (obj);
        }
    
        public void monodroidClearReferences ()
        {
            if (refList != null)
                refList.clear ();
        }
    }
    
  • static final String __md_methods; static { __md_methods = "n_getPackageName:()Ljava/lang/String;:GetGetPackageNameHandler\n" + ""; } 媒体资源的链接代码。

    PackageName
  • 注册码:

    public java.lang.String getPackageName ()
    {
        return n_getPackageName ();
    }
    
    private native java.lang.String n_getPackageName ();
    

现在,它在public void onCreate () { mono.android.Runtime.register ("TestApp.TestApplication, TestApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", TestApplication.class, __md_methods); super.onCreate (); } 调用时崩溃的最可能原因是因为n_getPackageName() android.app.Application方法在之前被称为 getPackageName()调用

如果您解剖onCreateMonoPackageManager,您会发现问题的原因:

MonoRuntimeProvider.java

MonoRuntimeProvider

MonoPackageManager.java

@Override
public void attachInfo (android.content.Context context, android.content.pm.ProviderInfo info)
{
    // Mono Runtime Initialization {{{
    android.content.pm.ApplicationInfo apiInfo = null;

    String platformPackage  = mono.MonoPackageManager.getApiPackageName ();
    if (platformPackage != null) {
        Throwable t = null;
        try {
            apiInfo = context.getPackageManager ().getApplicationInfo (platformPackage, 0);
        } catch (android.content.pm.PackageManager.NameNotFoundException e) {
            // ignore
        }
        if (apiInfo == null) {
            try {
                apiInfo = context.getPackageManager ().getApplicationInfo ("Xamarin.Android.Platform", 0);
            } catch (android.content.pm.PackageManager.NameNotFoundException e) {
                t = e;
            }
        }
        if (apiInfo == null)
            throw new RuntimeException ("Unable to find application " + platformPackage + " or Xamarin.Android.Platform!", t);
    }
    try {
        android.content.pm.ApplicationInfo runtimeInfo = context.getPackageManager ().getApplicationInfo ("Mono.Android.DebugRuntime", 0);
        mono.MonoPackageManager.LoadApplication (context, runtimeInfo.dataDir,
                apiInfo != null
                ? new String[]{runtimeInfo.sourceDir, apiInfo.sourceDir, context.getApplicationInfo ().sourceDir}
                : new String[]{runtimeInfo.sourceDir, context.getApplicationInfo ().sourceDir});
    } catch (android.content.pm.PackageManager.NameNotFoundException e) {
        throw new RuntimeException ("Unable to find application Mono.Android.DebugRuntime!", e);
    }
    // }}}
    super.attachInfo (context, info);
}

当您完成启动例程时,崩溃的原因变得清晰:

  • Android加载// ... public static void LoadApplication (Context context, String runtimeDataDir, String[] apks) { synchronized (lock) { if (!initialized) { System.loadLibrary("monodroid"); Locale locale = Locale.getDefault (); String language = locale.getLanguage () + "-" + locale.getCountry (); String filesDir = context.getFilesDir ().getAbsolutePath (); String cacheDir = context.getCacheDir ().getAbsolutePath (); String dataDir = context.getApplicationInfo ().dataDir + "/lib"; ClassLoader loader = context.getClassLoader (); Runtime.init ( language, apks, runtimeDataDir, new String[]{ filesDir, cacheDir, dataDir, }, loader, new java.io.File ( android.os.Environment.getExternalStorageDirectory (), "Android/data/" + context.getPackageName () + "/files/.__override__").getAbsolutePath (), MonoPackageManager_Resources.Assemblies, context.getPackageName ()); initialized = true; } } } // ... 类并执行MonoRuntimeProvider
  • attachInfo调用attachInfo
  • LoadApplication次调用使用应用程序上下文LoadApplication方法。
  • getPackageName()调用getPackageName()方法。

根据n_getPackageName()的文档:

  

public void onCreate()

     

在应用程序启动时,在创建任何活动,服务或接收方对象(不包括内容提供商)之前调用。实现应尽可能快(例如使用状态的延迟初始化),因为在此函数中花费的时间直接影响在进程中启动第一个活动,服务或接收器的性能。如果重写此方法,请务必调用super.onCreate()。

因为在ContentProviders onCreate之后调用了Applications onCreate,所以本机方法不会被Mono绑定,因此无法解析!因此,android.app.Application例外存在根本原因。

总而言之,这既是错误又是启动复杂性。