Dynamically load apk that uses resources

2020-07-30 02:21发布

I have service.apk that is using resources to show a notification in the status bar.

I am dynamically loading the class that is using these resources but then the resources for the notifications disappear somehow, and I'm getting this error:

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

The code that dynamically loads:

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

I'm thinking maybe the way I'm loading the apk is wrong? Maybe I should add a path for the resources?

Any Help would be very much appreciated!

2条回答
成全新的幸福
2楼-- · 2020-07-30 02:44

you can refer to the following open source project: https://github.com/singwhatiwanna/dynamic-load-apk/blob/master/README-en.md

following is the key thinking: first, apk can be loaded by host android application, ignored that it is on sdcard or on system directory. but how can we do this? two problems need to be resolved: resource and activity's lifecircle. the above project resolves this two problems, now, Dynamically load apk that uses resources is possible, use DexClassLoader and provide new AssetManager can satisfy your demand.

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());
}

then, resources can be visited by R identifer, use getResource.

查看更多
孤傲高冷的网名
3楼-- · 2020-07-30 02:48

To obtain resources from other apk, You need to use getResourcesForApplication(). It's obvious that main apk doesn't have that icon in it's generated R class, but Service one has. So, in the Service, whenever You're trying to access resources, it should look like:

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

Unfortunately, I think it'll not be possible to just pass iconId in notification and You'll need to load resource yourself before using in notification (e.g. setup RemoteViews and use Notification.Builder.setContent()).

查看更多
登录 后发表回答