Android 逆向工程 - 嵌入Admob SDK
一、用apktool将apk反编译
apktool工具下载链接:https://apktool.org
Demo A: 创建的空白项目,只有一个空白Activity
Demo B: 创建的空白项目,接入了admob SDK,并初始化-加载广告-展示广告
java -jar apktool_2.7.0.jar d app-release-a.apk // 反编译
操作还用到一个Python脚本 “diffFile.py”,用来区别两个文件的差异
import sys
import difflib
# 定义文件路径
xml_file1 = '/Users/XXXX/Desktop/Android Reverse/1-apktool/app-release-empty-a/AndroidManifest.xml'
xml_file2 = '/Users/XXXX/Desktop/Android Reverse/1-apktool/app-release-admob-b/AndroidManifest.xml'
# 读取文件内容
with open(xml_file1, 'r') as file1, open(xml_file2, 'r') as file2:
file1_data = file1.readlines()
file2_data = file2.readlines()
# 使用difflib比较文件
diff = difflib.unified_diff(file1_data, file2_data, fromfile=xml_file1, tofile=xml_file2)
# 重定向输出到result.txt
with open('result.txt', 'w') as result_file:
for line in diff:
result_file.write(line)
二、嵌入SDK
1、添加Admob相关的资源文件
将反编译后res文件夹下所有的资源文件,添加到Demo A中。
逐个目录检查,将Admob相关的资源文件添加进Demo A中。
其中对于values文件夹的,需要将文件内所有的xml文件逐个打开修改内容(除public.xml外)。
public.xml是一个汇总了所有资源文件信息的文件,其中包含资源文件名称以及对应的id。不过在本文档的流程中不需要手动修改其的内容。因为只需要将新增的资源文件添加完成后,重新打包public.xml会自动为新增的资源文件添加id。
以ids.xml文件为例子,可以使用本文章提供的 diffFile.py 脚本排查追加部分
到这建议先进行重打包在进行后续的代码嵌入操作,因为重打包能检查资源文件是否添加正确。后续流程如果报错也有可能是资源文件添加错误导致。
2、 修改AndroidManifest.xml文件
对比Demo A与Demo B的AndroidManifest.xml文件,并将Admob相关的追加到Demo A中
通过python脚本diffFile.py对比两者,排查其中与Admob相关的信息
因为包名在对比AndroidManifest.xml文件时会妨碍排查,所以我这边事先将两者的包名都替换为"com.hgw.resulttext"。
--- /Users/heguangwen/Desktop/Android Reverse/1-apktool/app-release-empty-a/AndroidManifest.xml
+++ /Users/heguangwen/Desktop/Android Reverse/1-apktool/app-release-admob-b/AndroidManifest.xml
@@ -1,7 +1,26 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" android:compileSdkVersion="34" android:compileSdkVersionCodename="14" package="com.hgw.resulttext" platformBuildVersionCode="34" platformBuildVersionName="14">
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="com.google.android.gms.permission.AD_ID"/>
+ <uses-permission android:name="android.permission.ACCESS_ADSERVICES_AD_ID"/>
+ <uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION"/>
+ <uses-permission android:name="android.permission.ACCESS_ADSERVICES_TOPICS"/>
+ <queries>
+ <intent>
+ <action android:name="android.intent.action.VIEW"/>
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <data android:scheme="https"/>
+ </intent>
+ <intent>
+ <action android:name="android.support.customtabs.action.CustomTabsService"/>
+ </intent>
+ </queries>
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<permission android:name="com.hgw.resulttext.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION" android:protectionLevel="signature"/>
<uses-permission android:name="com.hgw.resulttext.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"/>
- <application android:allowBackup="true" android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:dataExtractionRules="@xml/data_extraction_rules" android:extractNativeLibs="false" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.MyApplicationA">
+ <application android:allowBackup="true" android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:dataExtractionRules="@xml/data_extraction_rules" android:extractNativeLibs="false" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.MyApplicationB">
+ <meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="ca-app-pub-3940256099942544~3347511713"/>
<activity android:exported="true" android:name="com.hgw.resulttext.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@@ -9,11 +28,65 @@
</intent-filter>
<meta-data android:name="android.app.lib_name" android:value=""/>
</activity>
+ <activity android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:exported="false" android:name="com.google.android.gms.ads.AdActivity" android:theme="@android:style/Theme.Translucent"/>
+ <provider android:authorities="com.hgw.resulttext.mobileadsinitprovider" android:exported="false" android:initOrder="100" android:name="com.google.android.gms.ads.MobileAdsInitProvider"/>
+ <service android:enabled="true" android:exported="false" android:name="com.google.android.gms.ads.AdService"/>
+ <activity android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:exported="false" android:name="com.google.android.gms.ads.OutOfContextTestingActivity"/>
+ <activity android:excludeFromRecents="true" android:exported="false" android:launchMode="singleTask" android:name="com.google.android.gms.ads.NotificationHandlerActivity" android:taskAffinity="" android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
+ <property android:name="android.adservices.AD_SERVICES_CONFIG" android:resource="@xml/gma_ad_services_config"/>
+ <activity android:exported="false" android:name="com.google.android.gms.common.api.GoogleApiActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
+ <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>
<provider android:authorities="com.hgw.resulttext.androidx-startup" android:exported="false" android:name="androidx.startup.InitializationProvider">
<meta-data android:name="androidx.emoji2.text.EmojiCompatInitializer" android:value="androidx.startup"/>
+ <meta-data android:name="androidx.work.WorkManagerInitializer" android:value="androidx.startup"/>
<meta-data android:name="androidx.lifecycle.ProcessLifecycleInitializer" android:value="androidx.startup"/>
<meta-data android:name="androidx.profileinstaller.ProfileInstallerInitializer" android:value="androidx.startup"/>
</provider>
+ <uses-library android:name="android.ext.adservices" android:required="false"/>
+ <service android:directBootAware="false" android:enabled="@bool/enable_system_alarm_service_default" android:exported="false" android:name="androidx.work.impl.background.systemalarm.SystemAlarmService"/>
+ <service android:directBootAware="false" android:enabled="@bool/enable_system_job_service_default" android:exported="true" android:name="androidx.work.impl.background.systemjob.SystemJobService" android:permission="android.permission.BIND_JOB_SERVICE"/>
+ <service android:directBootAware="false" android:enabled="@bool/enable_system_foreground_service_default" android:exported="false" android:name="androidx.work.impl.foreground.SystemForegroundService"/>
+ <receiver android:directBootAware="false" android:enabled="true" android:exported="false" android:name="androidx.work.impl.utils.ForceStopRunnable$BroadcastReceiver"/>
+ <receiver android:directBootAware="false" android:enabled="false" android:exported="false" android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$BatteryChargingProxy">
+ <intent-filter>
+ <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
+ <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
+ </intent-filter>
+ </receiver>
+ <receiver android:directBootAware="false" android:enabled="false" android:exported="false" android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$BatteryNotLowProxy">
+ <intent-filter>
+ <action android:name="android.intent.action.BATTERY_OKAY"/>
+ <action android:name="android.intent.action.BATTERY_LOW"/>
+ </intent-filter>
+ </receiver>
+ <receiver android:directBootAware="false" android:enabled="false" android:exported="false" android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$StorageNotLowProxy">
+ <intent-filter>
+ <action android:name="android.intent.action.DEVICE_STORAGE_LOW"/>
+ <action android:name="android.intent.action.DEVICE_STORAGE_OK"/>
+ </intent-filter>
+ </receiver>
+ <receiver android:directBootAware="false" android:enabled="false" android:exported="false" android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$NetworkStateProxy">
+ <intent-filter>
+ <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
+ </intent-filter>
+ </receiver>
+ <receiver android:directBootAware="false" android:enabled="false" android:exported="false" android:name="androidx.work.impl.background.systemalarm.RescheduleReceiver">
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED"/>
+ <action android:name="android.intent.action.TIME_SET"/>
+ <action android:name="android.intent.action.TIMEZONE_CHANGED"/>
+ </intent-filter>
+ </receiver>
+ <receiver android:directBootAware="false" android:enabled="@bool/enable_system_alarm_service_default" android:exported="false" android:name="androidx.work.impl.background.systemalarm.ConstraintProxyUpdateReceiver">
+ <intent-filter>
+ <action android:name="androidx.work.impl.background.systemalarm.UpdateProxies"/>
+ </intent-filter>
+ </receiver>
+ <receiver android:directBootAware="false" android:enabled="true" android:exported="true" android:name="androidx.work.impl.diagnostics.DiagnosticsReceiver" android:permission="android.permission.DUMP">
+ <intent-filter>
+ <action android:name="androidx.work.diagnostics.REQUEST_DIAGNOSTICS"/>
+ </intent-filter>
+ </receiver>
<receiver android:directBootAware="false" android:enabled="true" android:exported="true" android:name="androidx.profileinstaller.ProfileInstallReceiver" android:permission="android.permission.DUMP">
<intent-filter>
<action android:name="androidx.profileinstaller.action.INSTALL_PROFILE"/>
@@ -28,5 +101,6 @@
<action android:name="androidx.profileinstaller.action.BENCHMARK_OPERATION"/>
</intent-filter>
</receiver>
+ <service android:directBootAware="true" android:exported="false" android:name="androidx.room.MultiInstanceInvalidationService"/>
</application>
</manifest>
将与Admob相关信息追加到Demo A中(这里为了方便查看追加部分保留了"+“,实际操作请将”+"去除)
<?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" android:compileSdkVersion="34" android:compileSdkVersionCodename="14" package="com.hgw.myapplicationa" platformBuildVersionCode="34" platformBuildVersionName="14">
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+ <uses-permission android:name="com.google.android.gms.permission.AD_ID"/>
+ <uses-permission android:name="android.permission.ACCESS_ADSERVICES_AD_ID"/>
+ <uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION"/>
+ <uses-permission android:name="android.permission.ACCESS_ADSERVICES_TOPICS"/>
+ <queries>
+ <intent>
+ <action android:name="android.intent.action.VIEW"/>
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <data android:scheme="https"/>
+ </intent>
+ <intent>
+ <action android:name="android.support.customtabs.action.CustomTabsService"/>
+ </intent>
+ </queries>
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<permission android:name="com.hgw.myapplicationa.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION" android:protectionLevel="signature"/>
<uses-permission android:name="com.hgw.myapplicationa.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"/>
<application android:allowBackup="true" android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:dataExtractionRules="@xml/data_extraction_rules" android:extractNativeLibs="false" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.MyApplicationA">
+ <meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="ca-app-pub-3940256099942544~3347511713"/>
<activity android:exported="true" android:name="com.hgw.myapplicationa.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data android:name="android.app.lib_name" android:value=""/>
</activity>
+ <activity android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:exported="false" android:name="com.google.android.gms.ads.AdActivity" android:theme="@android:style/Theme.Translucent"/>
+ <provider android:authorities="com.hgw.myapplicationa.mobileadsinitprovider" android:exported="false" android:initOrder="100" android:name="com.google.android.gms.ads.MobileAdsInitProvider"/>
+ <service android:enabled="true" android:exported="false" android:name="com.google.android.gms.ads.AdService"/>
+ <activity android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode" android:exported="false" android:name="com.google.android.gms.ads.OutOfContextTestingActivity"/>
+ <activity android:excludeFromRecents="true" android:exported="false" android:launchMode="singleTask" android:name="com.google.android.gms.ads.NotificationHandlerActivity" android:taskAffinity="" android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
+ <property android:name="android.adservices.AD_SERVICES_CONFIG" android:resource="@xml/gma_ad_services_config"/>
+ <activity android:exported="false" android:name="com.google.android.gms.common.api.GoogleApiActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
+ <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version"/>
<provider android:authorities="com.hgw.myapplicationa.androidx-startup" android:exported="false" android:name="androidx.startup.InitializationProvider">
<meta-data android:name="androidx.emoji2.text.EmojiCompatInitializer" android:value="androidx.startup"/>
+ <meta-data android:name="androidx.work.WorkManagerInitializer" android:value="androidx.startup"/>
<meta-data android:name="androidx.lifecycle.ProcessLifecycleInitializer" android:value="androidx.startup"/>
<meta-data android:name="androidx.profileinstaller.ProfileInstallerInitializer" android:value="androidx.startup"/>
</provider>
+ <uses-library android:name="android.ext.adservices" android:required="false"/>
+ <service android:directBootAware="false" android:enabled="@bool/enable_system_alarm_service_default" android:exported="false" android:name="androidx.work.impl.background.systemalarm.SystemAlarmService"/>
+ <service android:directBootAware="false" android:enabled="@bool/enable_system_job_service_default" android:exported="true" android:name="androidx.work.impl.background.systemjob.SystemJobService" android:permission="android.permission.BIND_JOB_SERVICE"/>
+ <service android:directBootAware="false" android:enabled="@bool/enable_system_foreground_service_default" android:exported="false" android:name="androidx.work.impl.foreground.SystemForegroundService"/>
+ <receiver android:directBootAware="false" android:enabled="true" android:exported="false" android:name="androidx.work.impl.utils.ForceStopRunnable$BroadcastReceiver"/>
+ <receiver android:directBootAware="false" android:enabled="false" android:exported="false" android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$BatteryChargingProxy">
+ <intent-filter>
+ <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
+ <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
+ </intent-filter>
+ </receiver>
+ <receiver android:directBootAware="false" android:enabled="false" android:exported="false" android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$BatteryNotLowProxy">
+ <intent-filter>
+ <action android:name="android.intent.action.BATTERY_OKAY"/>
+ <action android:name="android.intent.action.BATTERY_LOW"/>
+ </intent-filter>
+ </receiver>
+ <receiver android:directBootAware="false" android:enabled="false" android:exported="false" android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$StorageNotLowProxy">
+ <intent-filter>
+ <action android:name="android.intent.action.DEVICE_STORAGE_LOW"/>
+ <action android:name="android.intent.action.DEVICE_STORAGE_OK"/>
+ </intent-filter>
+ </receiver>
+ <receiver android:directBootAware="false" android:enabled="false" android:exported="false" android:name="androidx.work.impl.background.systemalarm.ConstraintProxy$NetworkStateProxy">
+ <intent-filter>
+ <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
+ </intent-filter>
+ </receiver>
+ <receiver android:directBootAware="false" android:enabled="false" android:exported="false" android:name="androidx.work.impl.background.systemalarm.RescheduleReceiver">
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED"/>
+ <action android:name="android.intent.action.TIME_SET"/>
+ <action android:name="android.intent.action.TIMEZONE_CHANGED"/>
+ </intent-filter>
+ </receiver>
+ <receiver android:directBootAware="false" android:enabled="@bool/enable_system_alarm_service_default" android:exported="false" android:name="androidx.work.impl.background.systemalarm.ConstraintProxyUpdateReceiver">
+ <intent-filter>
+ <action android:name="androidx.work.impl.background.systemalarm.UpdateProxies"/>
+ </intent-filter>
+ </receiver>
+ <receiver android:directBootAware="false" android:enabled="true" android:exported="true" android:name="androidx.work.impl.diagnostics.DiagnosticsReceiver" android:permission="android.permission.DUMP">
+ <intent-filter>
+ <action android:name="androidx.work.diagnostics.REQUEST_DIAGNOSTICS"/>
+ </intent-filter>
+ </receiver>
<receiver android:directBootAware="false" android:enabled="true" android:exported="true" android:name="androidx.profileinstaller.ProfileInstallReceiver" android:permission="android.permission.DUMP">
<intent-filter>
<action android:name="androidx.profileinstaller.action.INSTALL_PROFILE"/>
</intent-filter>
<intent-filter>
<action android:name="androidx.profileinstaller.action.SKIP_FILE"/>
</intent-filter>
<intent-filter>
<action android:name="androidx.profileinstaller.action.SAVE_PROFILE"/>
</intent-filter>
<intent-filter>
<action android:name="androidx.profileinstaller.action.BENCHMARK_OPERATION"/>
</intent-filter>
</receiver>
+ <service android:directBootAware="true" android:exported="false" android:name="androidx.room.MultiInstanceInvalidationService"/>
</application>
</manifest>
3、Admob相关代码嵌入
对比两者的依赖信息,并将与Admob相关的依赖或添加或更新到Demo A中。
通过执行androidDependencies获取打包时的依赖信息。
releaseRuntimeClasspath - Dependencies for runtime/packaging
通过diffFile.py脚本对比两者的依赖,确认Demo A哪些依赖需要添加,哪些依赖需要升级。
--- /Users/heguangwen/Desktop/Android Reverse/empty-a-dependencies
+++ /Users/heguangwen/Desktop/Android Reverse/admob-b-dependencies
@@ -3,7 +3,18 @@
+--- androidx.constraintlayout:constraintlayout:2.1.4@aar
+--- androidx.appcompat:appcompat-resources:1.6.1@aar
+--- androidx.appcompat:appcompat:1.6.1@aar
++--- com.google.android.gms:play-services-ads:22.6.0@aar
+--- androidx.viewpager2:viewpager2:1.0.0@aar
++--- com.google.android.gms:play-services-ads-lite:22.6.0@aar
++--- com.google.android.gms:play-services-ads-base:22.6.0@aar
++--- com.google.android.ump:user-messaging-platform:2.1.0@aar
++--- com.google.android.gms:play-services-ads-identifier:18.0.0@aar
++--- com.google.android.gms:play-services-appset:16.0.1@aar
++--- com.google.android.gms:play-services-base:18.0.0@aar
++--- com.google.android.gms:play-services-tasks:18.0.1@aar
++--- com.google.android.gms:play-services-measurement-sdk-api:20.1.2@aar
++--- com.google.android.gms:play-services-measurement-base:20.1.2@aar
++--- com.google.android.gms:play-services-basement:18.2.0@aar
+--- androidx.fragment:fragment:1.3.6@aar
+--- androidx.fragment:fragment:1.3.6@aar
+--- androidx.activity:activity:1.8.0@aar
@@ -15,11 +26,18 @@
+--- androidx.transition:transition:1.2.0@aar
+--- androidx.vectordrawable:vectordrawable-animated:1.1.0@aar
+--- androidx.vectordrawable:vectordrawable:1.1.0@aar
++--- androidx.browser:browser:1.4.0@aar
++--- androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05@aar
++--- androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05@aar
++--- androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05@aar
+--- androidx.legacy:legacy-support-core-utils:1.0.0@aar
+--- androidx.loader:loader:1.0.0@aar
+--- androidx.savedstate:savedstate:1.2.1@aar
++--- androidx.work:work-runtime:2.7.0@aar
++--- androidx.lifecycle:lifecycle-service:2.6.1@aar
+--- androidx.lifecycle:lifecycle-process:2.6.1@aar
+--- androidx.lifecycle:lifecycle-livedata-core:2.6.1@aar
++--- androidx.lifecycle:lifecycle-livedata:2.6.1@aar
+--- androidx.lifecycle:lifecycle-livedata:2.6.1@aar
+--- androidx.lifecycle:lifecycle-common:2.6.1@jar
+--- androidx.lifecycle:lifecycle-viewmodel:2.6.1@aar
@@ -41,21 +59,31 @@
+--- androidx.startup:startup-runtime:1.1.1@aar
+--- androidx.tracing:tracing:1.0.0@aar
+--- androidx.interpolator:interpolator:1.0.0@aar
++--- androidx.concurrent:concurrent-futures:1.1.0@jar
++--- androidx.room:room-runtime:2.2.5@aar
++--- androidx.arch.core:core-runtime:2.2.0@aar
+--- androidx.arch.core:core-runtime:2.2.0@aar
+--- androidx.arch.core:core-common:2.2.0@jar
-+--- androidx.concurrent:concurrent-futures:1.1.0@jar
+--- androidx.documentfile:documentfile:1.0.0@aar
+--- androidx.localbroadcastmanager:localbroadcastmanager:1.0.0@aar
+--- androidx.print:print:1.0.0@aar
-+--- androidx.annotation:annotation:1.3.0@jar
++--- androidx.sqlite:sqlite-framework:2.1.0@aar
++--- androidx.sqlite:sqlite:2.1.0@aar
++--- androidx.room:room-common:2.2.5@jar
+--- androidx.annotation:annotation-experimental:1.3.0@aar
-+--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4@jar
-+--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4@jar
++--- androidx.annotation:annotation-jvm:1.6.0@jar
++--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1@jar
++--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.1@jar
+--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22@jar
+--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22@jar
+--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22@jar
++--- com.google.guava:guava:31.1-android@jar
+--- com.google.errorprone:error_prone_annotations:2.15.0@jar
+--- androidx.constraintlayout:constraintlayout-core:1.0.4@jar
++--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava@jar
+--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22@jar
-+--- org.jetbrains:annotations:13.0@jar
-\--- com.google.guava:listenablefuture:1.0@jar
++--- org.jetbrains:annotations:23.0.0@jar
++--- com.google.guava:failureaccess:1.0.1@jar
++--- com.google.code.findbugs:jsr305:3.0.2@jar
++--- org.checkerframework:checker-qual:3.12.0@jar
+\--- com.google.j2objc:j2objc-annotations:1.3@jar
如何知道这个依赖带有了哪些代码呢?可以通过自行写一个Demo依赖来查看带有的代码。
在嵌入代码之前,先要了解到
为什么反编译后会拆分多个smali文件夹
因为在Android中,Java源代码首先被编译成Java字节码,然后再被转换成Dalvik字节码(DEX)。DEX文件包含了应用的所有代码,但是由于DEX文件格式的限制,每个DEX文件只能包含65536(即2的16次方)个方法引用。
当一个Android应用的方法数量超过这个限制时,就需要使用多个DEX文件,这就是所谓的multidex。在这种情况下,主DEX文件(classes.dex)包含应用的主要代码,其他DEX文件(如classes2.dex,classes3.dex等)包含额外的代码。
当你使用apktool反编译一个APK时,每个DEX文件都会被转换成一组smali文件。smali是一种汇编语言,用于表示Dalvik字节码。每个smali文件对应于Java源代码中的一个类。
所以,如果你看到一个应用被拆分成多个smali文件,那可能是因为这个应用的方法数量超过了单个DEX文件的限制,或者开发者选择将代码分割成多个部分以便于管理。
所以在嵌入代码的时候,最好是新增新的smali文件夹放入新的代码,就如下图。
代码嵌入完之后,建议先进行重打包在进行后续的嵌入广告代码的操作,因为重打包能检查代码嵌入是否正确,后续流程如果报错也有可能是SDK代码嵌入错误导致。
4、添加广告代码逻辑到Demo A
为Demo A嵌入广告代码
下图是Demo B的MainActivity展示Admob广告的代码逻辑,在onCreate的时候初始化并加载展示广告
下图是Demo A的MainActivity。
反编译之后因为内部类的原因,会拆分成多个类。
参照Demo B的smali代码给Demo A添加广告逻辑
MainActivity.smali:
添加展示逻辑
MainActivity$1.smali:
整个smali文件拷贝,然后改包名
MainActivity$1$1.smali:
同样整个smali文件拷贝,然后改包名
三、重新打包
// 重新打包apk
java -jar apktool_2.7.0.jar b app-release
// 重新签名apk
./apksigner sign -ks mytest-keystore.jks app-release.apk
四、安装运行
五、注意
该操作本人只在插屏广告场景做了实验,可以正常展示广告。但是由于其他广告类型可能会使用到不同的资源id,可能会有冲突的情况,在实际改动时可能还需要查找各个id的使用代码进行修改。