【问题标题】:Dynamically load apk that uses resources动态加载使用资源的 apk
【发布时间】:2014-02-26 20:04:54
【问题描述】:

我有 service.apk 正在使用资源在状态栏中显示通知。

我正在动态加载使用这些资源的类,但是通知的资源不知何故消失了,我收到了这个错误:

W/ResourceType( 1142): No known package when getting value for resource number 0x7f020001 W/StatusBarIconView( 1142): Icon not found in 2130837505: 7f020001 W/StatusBarIconView( 1142): No icon for slot android/0x20 W/ActivityManager( 941): crashApplication: trying to crash self! D/NotificationService( 941): onNotification error pkg=android tag=null id=32; will crashApplication(uid=1000, pid=941) W/StatusBar( 1142): removeNotification for unknown key: android.os.BinderProxy@41b166b8

动态加载的代码:

PathClassLoader classLoader =
                new PathClassLoader("system/app/ServiceImpl.apk",
                               ClassLoader.getSystemClassLoader());
              Class someClass =
            classLoader.loadClass("com.bla.ServiceImpl");
              Constructor<Class> ctor = someClass.getConstructor(Context.class);
              Object someObject = ctor.newInstance(context);

我在想也许我加载 apk 的方式是错误的?也许我应该为资源添加路径?

任何帮助将不胜感激!

【问题讨论】:

  • 这看起来会非常复杂,如果它甚至可能的话。在您认为这是实现它的方法方面,您真正想要实现的功能是什么?
  • service.apk 正在使用资源在状态栏(而不是下拉菜单)中显示通知,这只能使用资源。我需要动态加载该 service.apk 并让它仍然显示通知...
  • 但是您希望通过动态加载服务 apk 来实现什么?它不太可能做到你想象的那样。
  • @ChrisStratton 那是因为 service.apk 的代码位于与我加载它的位置不同的分区中。我必须这样做......
  • 但是你为什么要加载服务apk呢?您认为通过在属于您的应用程序用户 ID 的进程中启动它,而不是让系统以通常的方式将其作为自己的进程启动,您将能够做什么?这个资源问题可能会分散人们对这个不寻常方案的真正困难的注意力。

标签: android apk dynamic-loading


【解决方案1】:

可以参考以下开源项目: https://github.com/singwhatiwanna/dynamic-load-apk/blob/master/README-en.md

以下是关键思想: 首先,apk 可以由宿主 android 应用程序加载,忽略它在 sdcard 或系统目录上。但是我们该怎么做呢?需要解决两个问题:资源和活动的生命周期。上面的项目解决了这两个问题,现在,动态加载使用资源的apk是可能的,使用DexClassLoader并提供新的AssetManager可以满足你的需求。

protected void loadResources() {
    try {
        AssetManager assetManager = AssetManager.class.newInstance();
        Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
        addAssetPath.invoke(assetManager, mDexPath);
        mAssetManager = assetManager;
    } catch (Exception e) {
        e.printStackTrace();
    }
    Resources superRes = super.getResources();
    mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(),
            superRes.getConfiguration());
    mTheme = mResources.newTheme();
    mTheme.setTo(super.getTheme());
}

然后,资源可以被R标识符访问,使用getResource。

【讨论】:

  • 最好提供更多关于这个开源项目的作用以及它如何提供帮助的信息,一句话就可以了。
【解决方案2】:

要从其他apk获取资源,需要使用getResourcesForApplication()。很明显,主 apk 在其生成的R 类中没有该图标,但服务一有。 因此,在服务中,每当您尝试访问资源时,它应该如下所示:

Resources res = packageManager.getResourcesForApplication("com.your_service");
Drawable icon = res.getDrawable(iconId);

不幸的是,我认为不可能只在通知中传递iconId,并且您需要在使用通知之前自己加载资源(例如设置RemoteViews并使用Notification.Builder.setContent())。

【讨论】:

  • serviceImpl.apk 是在状态栏中发布图标的那个,为此它必须传递resource-id。所以我猜它不应该加载资源,因为资源存在于它的 apk 中。
  • 我相信你的猜测是错误的。如果您在另一个应用程序上下文中启动服务,它会按照我描述的方式工作。现在唯一可能的解决方案 - 自己加载资源,id 将不起作用,因为它没有出现在主应用程序中。可能您不需要使用 PathClassLoader 并使用正常方式(例如意图)启动服务 - 那么资源 ID 就不会有问题。
  • 我必须使用动态加载来加载该服务。这就是请求。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多