您当前的位置:首页 > 计算机 > 编程开发 > 安卓(android)开发

提取系统apk

时间:02-08来源:作者:点击数:

提取系统apk

公司有个Android设备,里面内置了一款厂家自带的应用,该应该里面有一些提示语音,我想要把厂家的应用提取出来,以便获取应用内的语音资源,于是安装了一个APK Extractor,但是这个应用里没有列出来我需要的应用,系统应用也显示了,就是没有显示我需要的那个应用。经过百度,找到了另一种提取方式,成功的提取到了我需要的apk。

  1. 通过adb命令列出Android设备中的所有应用
    adb shell pm list packages
    
    效果如下:
    在这里插入图片描述
    确认这些包名里面有你需要的应用的包名,可以把这些包名复制到记事本,然后按搜索来查找是否有自己需要的应用的包名。关于如何知道需要的应用的包名是什么,可查看文后的“获取运行在最前面的应用的包名”章节。
  2. 查看自己需要的应用的保存路径,假设想要查看的应用包名为:rst.rst3.hc_client,操作如下:
    adb shell pm path rst.rst3.hc_client
    
    执行这个命令后,就能看到rst.rst3.hc_client包名的应用的保存位置了,如下:
    在这里插入图片描述
    这里的保存位置在/data/app/目录下,在这个目录下的apk都是属于系统apk的。
  3. 获取apk,在上一步中,我们已经查到了所需要apk的保存位置,复制这个路径,然后操作如下:
    adb pull /data/app/rst.rst3.hc_client-1/base.apk
    
    执行效果如下:
    在这里插入图片描述
    这说明我们已经成功的把apk保存到电脑中了,上面的命令中我们没有指定保存的路径,则默认会保存到当前位置,上面命令行中的当前位置为Even,所以我们在Even目录中就能看到刚刚获取的名为base.apk的应用了,用压缩软件把apk解压,然后就可以获取到里面的资源文件了,像音频类型的资源,一般会保存在asserts目录中,或者是保存在res/raw目录中。
    通过这种方式,不但能获取普通的应用,就连系统应用也是可以获取到的。比如在这个示例中,/data/app/目录中保存的就是系统应用。

获取运行在最前面的应用的包名

如何知道一个未知应用的包名,方法是我们可以把未知包名的应用运行起来,且让它运行在最前面。然后我们可以写一个程序来检测运行在最前面的应用的包名,在我的一个项目中,有一个检测当前运行在最前面的程序的服务类,如果检测到最前面的程序不是我们的app时,就会把自己的app运行在最前面,比较流氓。这里我就直接把代码复制过来了(目前在Android 7.1上测试是OK的,在更高的版本不知道是否还可以),代码如下:

/**
 * 栈顶app检查
 */
class StackTopAppCheckService : Service() {

    private lateinit var powerManager: PowerManager

    companion object {
        var needMoveToTop = true
    }

    override fun onBind(intent: Intent): IBinder? = null

    private var run = false

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        if (run) {
            // 如果检查任务已经在运行了,则直接返回
            return super.onStartCommand(intent, flags, startId)
        }

        run = true
        val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        thread {
            try {
                while (run) {
                    checkStackTopApp(activityManager)
                    Thread.sleep(6000) // 每6秒钟检测一次
                }
            } catch (e: Exception) {
                Timber.fw(e, "检查App是否在栈顶时出现异常")
            }
            Timber.fi("while循环执行结束")

            // 恢复变量
            run = false
        }

        return super.onStartCommand(intent, flags, startId)
    }

    private fun checkStackTopApp(activityManager: ActivityManager) {
        if (!isRunningForeground(activityManager)) { // 如果不在栈顶,则移到栈顶
            Timber.fw("我们的应用不在栈顶,当前栈顶应用为:${getStackTopAppPackageName(activityManager)},needMoveToTop = $needMoveToTop")
            if (needMoveToTop) {  // 有时候不希望一直弹到前台,则会把此变量设置为false
                moveToStackTop(activityManager)
            }
        }
    }


    fun getStackTopAppPackageName(activityManager: ActivityManager? = null): String {
        val manager = activityManager ?: getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        return manager.runningAppProcesses?.find {
            it.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
        }?.processName ?: "未知"
    }

    /** 把执法仪移动到栈顶 */
    @Suppress("DEPRECATION")
    private fun moveToStackTop(activityManager: ActivityManager) {
        activityManager.getRunningTasks(100)?.find { it.topActivity?.packageName == App.getContext().packageName }?.let {
            activityManager.moveTaskToFront(it.id, 0)
        }
    }

    /** 判断本应用是否已经位于最前端:已经位于最前端时,返回 true;否则返回 false */
    private fun isRunningForeground(activityManager: ActivityManager): Boolean {
        return activityManager.runningAppProcesses?.any {
            it.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
            && it.processName == App.getContext().applicationInfo.processName
        } ?: false
    }



    override fun onCreate() {
        super.onCreate()
        Timber.fi("onCreate")
        powerManager = App.getContext().powerManager
    }

    override fun onDestroy() {
        super.onDestroy()
        Timber.fi("onDestroy")
        run = false
    }

}
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门