Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/183.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android Xamarin中的PackageName属性重写错误_Android_Xamarin_Xamarin.android - Fatal编程技术网

Android Xamarin中的PackageName属性重写错误

Android Xamarin中的PackageName属性重写错误,android,xamarin,xamarin.android,Android,Xamarin,Xamarin.android,[附件项目文件:] 我试图覆盖应用程序PackageName属性。但发生了java.lang.UnsatisfiedLinkError(未找到本机方法)。所以我在谷歌搜索这个问题,我发现了一个关于完全相同的问题()。但不幸的是,没有答案。我能做些什么来解决这个问题 [Application] public class TestApplication : Application { public override string PackageName { get

[附件项目文件:]

我试图覆盖应用程序PackageName属性。但发生了java.lang.UnsatisfiedLinkError(未找到本机方法)。所以我在谷歌搜索这个问题,我发现了一个关于完全相同的问题()。但不幸的是,没有答案。我能做些什么来解决这个问题

[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)

这看起来像是MonoAndroid中的一个限制和一个bug;发生
java.lang.UnsatifiedLinkError
异常,因为方法
n_getPackageName
尚未在Mono运行时注册,并且无法解析。简单的回答是:

  • 由于MonoAndroids启动序列的复杂性,可能无法覆盖
    应用程序的
    PackageName
    属性
  • 向Xamarin提交错误报告。这是MonoAndroid启动例程中的一个bug(如下所述)
下兔子洞 让我们深入研究桥接Java代码,以确定发生这种情况的原因。构建MonoAndroid应用程序时,会在项目的
[ProjectName]/obj/[Configuration]/android/src
目录中生成一组Java代码。这段源代码是互操作层,它允许用C#构建的应用程序通过Dalvik或ART在Android设备上执行。项目中作为Android组件的每个类(
应用程序
服务
活动
片段
等)都将生成相应的.java源代码文件

这是您的
TestApp
类的一个:

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 ();
    }
}
这里需要注意的重要事项是:

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

    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\u getPackageName()
调用时崩溃的最可能原因是
android.app.Application
s
getPackageName()
方法在
onCreate
调用之前被调用

然后,如果仔细分析
MonoPackageManager
MonoRuntimeProvider
,就会找到问题的原因:

MonoRuntimeProvider.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);
}
MonoPackageManager.java

// ...
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;
        }
    }
}
// ...
当您完成启动例程时,崩溃的原因就会变得很清楚:

  • Android加载
    MonoRuntimeProvider
    类并执行
    attachInfo
  • attachInfo
    调用
    LoadApplication
  • LoadApplication
    调用使用应用程序上下文
    getPackageName()
    方法
  • getPackageName()
    调用
    n\u getPackageName()
    方法
根据android.app.Application
的文档:

public void onCreate()

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

因为在ContentProviders onCreate之后调用Applications onCreate,所以本机方法不会被Mono绑定,因此无法解析!因此,
java.lang.UnsatifiedLinkError
异常的根本原因就在这里


总而言之,这既是一个bug,也是一个启动复杂性。

在Activity案例中,注册码在静态构造函数中调用,继承的PackageName属性运行良好。若我修改apk文件以调用静态构造函数类活动的注册码,那个么就并没有错误了?不用担心,我喜欢解决一个好问题;这个比我原来想的要复杂得多;)不要修改apk;这通常不是好的做法。为什么需要更改
PackageName
的返回值?我希望这样。答案是在应用程序中重写getPackageName。正如我所希望的那样,它在Java中运行良好。