Skip to content

Fix Bundle.main asset path when DRM wrapper replaces applicationInfo.…#123

Closed
m-t-a-p wants to merge 2 commits into
skiptools:mainfrom
m-t-a-p:main
Closed

Fix Bundle.main asset path when DRM wrapper replaces applicationInfo.…#123
m-t-a-p wants to merge 2 commits into
skiptools:mainfrom
m-t-a-p:main

Conversation

@m-t-a-p

@m-t-a-p m-t-a-p commented Jun 1, 2026

Copy link
Copy Markdown

Problem

When apps are installed via Google Play, a DRM protection system called PairIP (com.pairip.*) wraps apps by replacing applicationInfo.className with a custom
Application subclass (e.g. com.pairip.application.AppController).

Bundle.main derives its asset package path from applicationInfo.className:

case .main:
    let identifer = Self.packageName(forClassName: applicationInfo.className)
    self.bundleURL = Self.createBundleURL(forPackage: identifer)

With PairIP active, packageName(forClassName:) produces com.pairip.application instead of the app's actual Kotlin namespace (e.g. what.watt), so Bundle.main resolves
to asset:/com/pairip/application/Resources — which doesn't exist. Since NSLocalizedString() defaults to Bundle.main, all translations fail silently (raw keys
returned instead of strings). The bug only manifests on Google Play installs; direct APK installs are unaffected because PairIP is not injected.

Why not use androidContext.packageName? It returns the applicationId (e.g. ch.whatwatt.app) — the Play Store identifier — which is not the Kotlin namespace used
for asset paths (e.g. what.watt). Apps routinely differ these two values, so packageName would break direct APK installs where applicationInfo.className is correct.

Fix

After deriving the package name as before (fast path unchanged), validate it by checking whether assets.list(derivedPath/Resources) returns any entries. If empty —
indicating the derived path is wrong — search the top two levels of the asset tree for a directory containing a Resources subdirectory.

@marcprux

marcprux commented Jun 2, 2026

Copy link
Copy Markdown
Member

Thanks again for all the work you've put into finding and fixing this issue.

I think there is still a shortcoming in this technique that #124 fixes, which is that this PR will assume that the first Resources/ folder in the assets is the Bundle.main. That won't work when there are multiple modules that each have their own Resources/, and if the package of the Main bundle happens to have more elements than one of the modules.

For example, you might have:

assets/com/example/app/main/Resources/someres.txt  <-- main bundle ComExampleAppMain
assets/com/example/utils/Resources/someutil.txt    <-- util bundle ComExampleUtils

In this case, Bundle.main will return the assets for ComExampleUtils since it is the first one found, right?

Could you try applying #124 and see if it also fixes your situation, if convenient?

@marcprux

marcprux commented Jun 3, 2026

Copy link
Copy Markdown
Member

Closing in favor of alternative fix in #124

@marcprux marcprux closed this Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants