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的使用代码进行修改。

  • 26
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 Android 应用中接入 AdMob 广告,需要进行以下步骤: 1. 注册 AdMob 账号并创建广告单元 2. 在 Android Studio 中添加 AdMob SDK 3. 在 AndroidManifest.xml 文件中添加必要的权限和服务 4. 在布局文件中添加 AdView 控件 5. 在代码中加载广告并显示 以下是一个简单的示例: 1. 注册 AdMob 账号并创建广告单元 在 AdMob 的网站上注册账号,并创建一个广告单元。记下广告单元 ID,稍后将用到。 2. 在 Android Studio 中添加 AdMob SDK 在 app 模块的 build.gradle 文件中添加以下依赖: ```groovy implementation 'com.google.android.gms:play-services-ads:20.4.0' ``` 3. 在 AndroidManifest.xml 文件中添加必要的权限和服务 添加以下权限: ```xml <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> ``` 添加以下服务: ```xml <service android:name="com.google.android.gms.ads.AdService" android:exported="false" /> ``` 4. 在布局文件中添加 AdView 控件 在需要显示广告的布局文件中添加 AdView 控件: ```xml <com.google.android.gms.ads.AdView android:id="@+id/adView" android:layout_width="wrap_content" android:layout_height="wrap_content" ads:adSize="BANNER" ads:adUnitId="YOUR_AD_UNIT_ID" /> ``` 将 `adUnitId` 替换为你的广告单元 ID。 5. 在代码中加载广告并显示 在 Activity 或 Fragment 中加载广告并显示: ```java import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.AdView; public class MainActivity extends AppCompatActivity { private AdView mAdView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 加载 AdView 控件 mAdView = findViewById(R.id.adView); // 创建广告请求 AdRequest adRequest = new AdRequest.Builder().build(); // 加载广告 mAdView.loadAd(adRequest); } @Override protected void onPause() { // 暂停广告 mAdView.pause(); super.onPause(); } @Override protected void onResume() { super.onResume(); // 恢复广告 mAdView.resume(); } @Override protected void onDestroy() { // 销毁广告 mAdView.destroy(); super.onDestroy(); } } ``` 以上就是接入 AdMob 广告的基本步骤。需要注意的是,为了获得更好的广告收益,建议遵循 Google 的广告政策并遵守良好的用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值