如何以编程方式获取应用的真实包名(而非Application ID)?
获取Android应用模块的真实包名与R类
我刚好遇到过类似的场景——库模块需要访问主应用的R类,而context.getPackageName()返回的是Build配置里的Application ID,和AndroidManifest中生成R类的真实包名可能不一致。下面分两部分解决你的问题:
一、获取AndroidManifest中的真实包名
要拿到生成R类的那个原始包名,最可靠的方式是解析APK中的AndroidManifest.xml文件,读取其package属性:
import android.content.Context import org.xmlpull.v1.XmlPullParser import org.xmlpull.v1.Xml.newPullParser import java.io.FileInputStream fun getRealManifestPackageName(context: Context): String? { val apkFilePath = context.applicationInfo.sourceDir val xmlParser: XmlPullParser = newPullParser() return try { xmlParser.setInput(FileInputStream(apkFilePath), "utf-8") var eventType = xmlParser.eventType while (eventType != XmlPullParser.END_DOCUMENT) { if (eventType == XmlPullParser.START_TAG && xmlParser.name == "manifest") { // 直接获取manifest标签的package属性 return xmlParser.getAttributeValue(null, "package") } eventType = xmlParser.next() } null } catch (e: Exception) { e.printStackTrace() null } }
这个方法会直接读取APK中打包后的Manifest文件,拿到的就是生成R类的真实包名,不受Application ID修改的影响。
二、获取主应用的R类
有两种常用方式,按需选择:
方式1:通过反射动态获取
拿到真实包名后,直接反射加载R类:
fun getAppRClass(context: Context): Class<*>? { val realPackageName = getRealManifestPackageName(context) ?: return null return try { // 加载主应用的R类 Class.forName("$realPackageName.R") } catch (e: ClassNotFoundException) { e.printStackTrace() null } }
注意:混淆配置
如果主应用开启了代码混淆,需要在ProGuard规则中添加以下配置,避免R类被混淆:
-keep class **.R { *; } -keep class **.R$* { *; }
方式2:主应用主动传入(更稳定)
反射毕竟有一定的不确定性,最好的方式是让主应用在初始化你的库时,直接传入R类的Class对象:
// 你的库模块中的初始化类 object MyLibrary { lateinit var appRClass: Class<*> fun init(context: Context, appRClass: Class<*>) { this.appRClass = appRClass // 其他初始化逻辑 } } // 主应用的Application类中调用初始化 class MyApp : Application() { override fun onCreate() { super.onCreate() MyLibrary.init(this, R::class.java) } }
这种方式完全避免了反射的问题,而且更加高效可靠,推荐在生产环境中使用。
内容的提问来源于stack exchange,提问作者avin
相关产品推荐
相关产品推荐

