Android 备份(提取)apk

article/2025/9/13 18:47:49

本文介绍两种提取完整apk(系统预装的和用户安装的)

一、通过adb提取(适合开发者)

    1. adb shell pm list packages找到要提取apk的包名

F:\winadb>adb shell pm list packages
package:com.android.fmradio
package:com.mediatek.gba
package:com.mediatek.ims
package:com.android.cts.priv.ctsshim
package:com.google.android.youtube
package:org.simalliance.openmobileapi.uicc2terminal
package:com.google.android.ext.services
package:com.android.providers.telephony
...


   2. adb shell pm path 定位apk所在系统路径

F:\winadb>adb shell pm path com.google.android.youtube
package:/system/app/YouTube/YouTube.apk

   

   3. adb pull <remote> [<local>] 从手机把apk pull下来

F:\winadb>adb pull /system/app/YouTube/YouTube.apk
9745 KB/s (31047955 bytes in 3.111s)


  这样三步就把想要的apk pull下来了,但是有个问题,执行第1步时,会dump很多包名,怎么确定那个包名是自己想要提取的apk吗?有些熟悉apk对应的包名一眼就认出来,但是对一个陌生的apk,是很难确定包名的。

二、app实现提取(适合大众)

比如坐高铁(或火车),看见隔壁的小伙伴玩的某款游戏,好像挺有意思,也想玩一下,好不容易向人家问到了,App名字,但是高速奔跑的高铁上没有WIFI,4G/3G网络(2G就不考虑了)又不好,怎么下载呢?如果能离线传输岂不更好?的确有,比如蓝牙、WIFI P2P(WIFI直连)都可以传输文件。这种情况还得apk在手机存储卡,否则也无法分享了。

下面就介绍通过app的方式将app(系统预装的和用户安装的)提取到手机存储(sdcard),实现的原理就像shell命令cp,java的实现是通过文件输入/输出流进行拷贝。(思路借鉴快牙app)

先上一张图,左边是快牙app,右边是本文说的demo


demo上面三个按钮用于过滤显示系统应用和用户自己安装的应用,每个item显示应用的图标、应用的名称、应用的包名、应用所在系统路径,一一对应,很容找到想要备份的apk了,长按弹出ContextMenu即可备份,代码比较简单,就一个类,直接贴出来了

package com.android.backupapp;import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;import com.android.backupapp.R.string;import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.UserHandle;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnCreateContextMenuListener;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;public class MainActivity extends Activity implementsOnCreateContextMenuListener, OnClickListener {private PackageManager mPackageManager;private Button mBtnAllApps;private Button mBtnSystemApps;private Button mBtnDataApps;private ListView mListView;private AppListAdapter mAdapter;public int MID;private static final String BACKUP_PATH = "/sdcard/Backup/";private static final String APK = ".apk";private static final String ODEX = ".odex";private static final String OAT32 = "oat/arm";private static final String OAT64 = "oat/arm64";public static enum AppType {SYSTEM, DATA, ALL}private static final int EVENT_COMPLETE = 1;private Handler mH = new Handler() {public void handleMessage(Message msg) {switch (msg.what) {case EVENT_COMPLETE:Toast.makeText(MainActivity.this, (String) msg.obj,Toast.LENGTH_SHORT).show();break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mListView = (ListView) findViewById(R.id.listview);mListView.setOnCreateContextMenuListener(this);mBtnAllApps = (Button) findViewById(R.id.all_apps);mBtnSystemApps = (Button) findViewById(R.id.system_apps);mBtnDataApps = (Button) findViewById(R.id.data_apps);mBtnAllApps.setOnClickListener(this);mBtnSystemApps.setOnClickListener(this);mBtnDataApps.setOnClickListener(this);mPackageManager = getPackageManager();List<PackageInfo> lists = mPackageManager.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);Collections.sort(lists, new DisplayNameComparator(mPackageManager));mAdapter = new AppListAdapter(this, lists);mListView.setAdapter(mAdapter);}@Overridepublic void onClick(View view) {// TODO Auto-generated method stubif (view == mBtnAllApps) {if (mAdapter.getAppType() != AppType.ALL) {mAdapter.setAppType(AppType.ALL);mAdapter.notifyDataSetChanged();}} else if (view == mBtnSystemApps) {if (mAdapter.getAppType() != AppType.SYSTEM) {mAdapter.setAppType(AppType.SYSTEM);mAdapter.notifyDataSetChanged();}} else if (view == mBtnDataApps) {if (mAdapter.getAppType() != AppType.DATA) {mAdapter.setAppType(AppType.DATA);mAdapter.notifyDataSetChanged();}}}@Overridepublic void onCreateContextMenu(ContextMenu menu, View v,ContextMenuInfo menuInfo) {// TODO Auto-generated method stubMenuInflater inflater = new MenuInflater(this);inflater.inflate(R.menu.context_menu, menu);super.onCreateContextMenu(menu, v, menuInfo);}@Overridepublic boolean onContextItemSelected(MenuItem item) {// TODO Auto-generated method stubAdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();MID = (int) info.id;PackageInfo pi = mAdapter.getItem(MID);switch (item.getItemId()) {case R.id.backup:backupApp(pi);return true;}return super.onContextItemSelected(item);}private Drawable getAppIcon(PackageInfo packageInfo) {return packageInfo.applicationInfo.loadIcon(mPackageManager);}private String getAppName(PackageInfo packageInfo) {return packageInfo.applicationInfo.loadLabel(mPackageManager).toString();}private String getAppPackageName(PackageInfo packageInfo) {return packageInfo.packageName;}private String getAppSourceDir(PackageInfo packageInfo) {return packageInfo.applicationInfo.sourceDir;}private void backupApp(PackageInfo packageInfo) {String source = getAppSourceDir(packageInfo);if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {String key = getAppName(packageInfo);String dest = BACKUP_PATH + key + APK;Toast.makeText(this, R.string.backup_start, Toast.LENGTH_SHORT).show();new Thread(new CopyRunnable(source, dest, key)).start();} else {String path = new File(source).getParent();String name = new File(source).getName();name = name.substring(0, name.indexOf(APK));String kitKat = new File(path).getParent() + File.separator + name+ ODEX;String oat32 = path + File.separator + OAT32 + File.separator+ name + ODEX;String oat64 = path + File.separator + OAT64 + File.separator+ name + ODEX;if (!new File(kitKat).exists() && !new File(oat32).exists()&& !new File(oat64).exists()) {String key = getAppName(packageInfo);if (getAppIcon(packageInfo).equals(getAppPackageName(packageInfo))) {key = name;}String dest = BACKUP_PATH + key + APK;Toast.makeText(this, R.string.backup_start, Toast.LENGTH_SHORT).show();new Thread(new CopyRunnable(source, dest, key)).start();} else {Toast.makeText(this, R.string.apk_has_oat, Toast.LENGTH_SHORT).show();}}}private class CopyRunnable implements Runnable {private String source;private String dest;private String key;public CopyRunnable(String source, String dest, String key) {this.source = source;this.dest = dest;this.key = key;}@Overridepublic void run() {// TODO Auto-generated method stubtry {int length = 1024 * 1024;if (!new File(BACKUP_PATH).exists()) {new File(BACKUP_PATH).mkdirs();}File fDest = new File(dest);if (fDest.exists()) {fDest.delete();}fDest.createNewFile();FileInputStream in = new FileInputStream(new File(source));FileOutputStream out = new FileOutputStream(fDest);FileChannel inC = in.getChannel();FileChannel outC = out.getChannel();int i = 0;while (true) {if (inC.position() == inC.size()) {inC.close();outC.close();Message message = mH.obtainMessage(EVENT_COMPLETE);message.obj = MainActivity.this.getString(R.string.backup_success, key, dest);mH.sendMessage(message);break;}if ((inC.size() - inC.position()) < 1024 * 1024) {length = (int) (inC.size() - inC.position());} else {length = 1024 * 1024;}inC.transferTo(inC.position(), length, outC);inC.position(inC.position() + length);i++;}} catch (Exception e) {// TODO: handle exceptionLog.e("zhouyj", e.toString());}}}private class AppListAdapter extends BaseAdapter {private Context context;private List<PackageInfo> lists;private AppType appType = AppType.DATA;public AppListAdapter(Context context, List<PackageInfo> lists) {this.context = context;this.lists = lists;}public AppType getAppType() {return appType;}public void setAppType(AppType appType) {this.appType = appType;}private List<PackageInfo> getDataList(AppType appType) {List<PackageInfo> l = new ArrayList<PackageInfo>();switch (appType) {case SYSTEM:for (PackageInfo pi : lists) {if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {l.add(pi);}}break;case DATA:for (PackageInfo pi : lists) {if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {l.add(pi);}}break;case ALL:return lists;}return l;}@Overridepublic int getCount() {// TODO Auto-generated method stubreturn getDataList(getAppType()).size();}@Overridepublic PackageInfo getItem(int position) {// TODO Auto-generated method stubreturn getDataList(getAppType()).get(position);}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {// TODO Auto-generated method stubPackageInfo pi = getItem(position);ViewHolder viewHolder = null;if (convertView == null) {viewHolder = new ViewHolder();LayoutInflater mInflater = LayoutInflater.from(context);convertView = mInflater.inflate(R.layout.layout_item, null);viewHolder.imageView = (ImageView) convertView.findViewById(R.id.drawable);viewHolder.tvAppName = (TextView) convertView.findViewById(R.id.app_name);viewHolder.tvPackageName = (TextView) convertView.findViewById(R.id.package_name);viewHolder.tvPath = (TextView) convertView.findViewById(R.id.app_path);convertView.setTag(viewHolder);} else {viewHolder = (ViewHolder) convertView.getTag();}viewHolder.imageView.setImageDrawable(getAppIcon(pi));viewHolder.tvAppName.setText(getAppName(pi));viewHolder.tvPackageName.setText(getAppPackageName(pi));viewHolder.tvPath.setText(getAppSourceDir(pi));return convertView;}}private static class ViewHolder {ImageView imageView;TextView tvAppName;TextView tvPackageName;TextView tvPath;}public static class DisplayNameComparator implementsComparator<PackageInfo> {public DisplayNameComparator(PackageManager pm) {mPM = pm;mCollator.setStrength(Collator.PRIMARY);}public final int compare(PackageInfo a, PackageInfo b) {// We want to put the one targeted to another user at the end of the// dialog.CharSequence sa = a.applicationInfo.loadLabel(mPM);if (sa == null)sa = a.packageName;CharSequence sb = b.applicationInfo.loadLabel(mPM);if (sb == null)sb = b.packageName;return mCollator.compare(sa.toString(), sb.toString());}private final Collator mCollator = Collator.getInstance();private PackageManager mPM;}}

Demo完整下载

http://chatgpt.dhexx.cn/article/cWxSveFd.shtml

相关文章

android数据恢复实现,安卓手机的数据恢复与备份

手机数据恢复 大多数人丢失手机最担心的应该就是众多的联系人信息和手机内的照片等内容。除了可以依靠软件来进行恢复&#xff0c;个别第三方ROM也具备类似功能&#xff0c;下面就一一介绍给大家。 使用Android手机的朋友可能都有一个谷歌账户(即Gmail邮箱)&#xff0c;首先来回…

7个适用于安卓手机的数据恢复工具

如果您发现某个重要文件已从您的 Android 手机或平板电脑中删除&#xff0c;那真是一个令人心碎的时刻。也许该文件反映了您无法重温的快乐时光&#xff0c;或者它是您在工作中需要的文件。 无论如何&#xff0c;丢失文件都是痛苦的。您可能在 Android 或iOS中丢失数据的原因可…

好用的电脑备份软件推荐

现在几乎每个人都有一台电脑&#xff0c;上面存储着大量的数据&#xff0c;比如宝贵的照片、视频、工作文档等等。但电脑也随时存在许多威胁&#xff0c;比如病毒、Windows 更新错误、死机黑屏、驱动程序问题、系统崩溃等。为防止任何数据丢失&#xff0c;你需要一个专业的电脑…

android 手机数据备份,安卓手机如何备份数据

安卓手机如何备份数据 在用电脑的时候&#xff0c;我们经常备份电脑里面的重要数据&#xff0c;以免电脑出现问题丢失数据;在用手机时也要养成经常备份的习惯&#xff0c;以免手机出现意外时手机内的重要数据丢失。 步骤1&#xff1a;先进入手机的设置→开发者选项&#xff0c;…

如何全备份android固件,如何一键备份安卓手机操作系统

如何一键备份安卓手机操作系统 【第一种情况&#xff0c;新系统不好用&#xff0c;想换回原系统】 我们要做的就是提前完整的备份下你的系统&#xff1a; 1、进recovery界面(进recovery模式的方法很多&#xff0c;按住音量下键光感键开机键;或者rom manager和热重启等软件都可以…

5款靠谱的安卓备份应用

1、App Backup & Restore 恢复你安装的所有应用很简单&#xff0c;只要进入Google Play商店&#xff0c;点击我的应用&#xff0c;重新安装你需要的&#xff0c;但是有时候你可能希望把这些应用备份到一个SD卡上&#xff0c;这样你就可以在批处理模式下快速恢复。这时候就需…

如何备份android10,安卓手机系统怎么备份

在用电脑的时候&#xff0c;我们经常备份电脑里面的重要数据&#xff0c;那么大家知道安卓手机系统怎么备份吗?今天学习啦小编与大家分享下安卓手机系统备份的具体操作步骤&#xff0c;有需要的朋友不妨了解下。 安卓手机系统备份方法一 在手机上如何备份系统和恢复系统的?首…

简单好用的苹果手机软件数据备份软件

苹果手机软件备份用哪个软件&#xff1f;虽然iTunes也能备份苹果手机软件&#xff0c;但只能整机备份&#xff0c;下面会介绍一款软件可仅备份软件的。手机用什么备份照片和视频&#xff1f;可以参照以下的操作进行照片和视频的备份。 一、苹果手机软件备份用哪个软件 苹果手…

android 手机数据备份,安卓手机怎么备份手机应用数据?安卓手机免root完整备份教程...

换新手机本该是件高兴的事情&#xff0c;可备份手机数据真的让人头疼。现在很多手机都内置备份程序&#xff0c;但只能备份简单的联系人、信息之类的数据&#xff0c;手机应用数据是没办法备份的。所以不少人在换机之前都会使用钛备份对手机进行root操作&#xff0c;再对手机进…

安卓手机备份_备份安卓手机中的APK安装文件?小编这儿有4种方法!

点击上方电脑爱好者关注我们 由于Android手机没有统一的应用商店,所以有些冷门APP的下载渠道并不稳定,经常出现因手机丢失或更换而再也找不到资源的尴尬情况。此外,当我们向朋友推荐好用或好玩的APP时,也经常出现短时间找不到下载地址的问题。此时,将手机中已安装的APP提取…

HTML设置跨行跨列

rowspan“2” 属性设置跨行 colspan“2” 属性设置跨列 &#xff08;数字根据你需要合并的格数选择) 跨行跨列后需将多出来的单元格删除&#xff08;Ctrlx&#xff09; 下面展示一些 跨行跨列代码片。 <!DOCTYPE html> <html lang"zh_CN"> <head&g…

table标签、表格的跨行跨列、ifarme标签

table标签 需求&#xff1a; 制作一个带表头的三行山列的表格&#xff0c;并显示边框&#xff1b;修改表格的宽度、高度、表格的对齐方式、单元格间距。 <!DOCTYPE html> <html lang"zh_CN"> <head><meta charset"UTF-8"><t…

用JS点击实现一个跨行/跨列显示的效果

一、目标样式 1、实现偶数行显色 2、在点击之后&#xff0c;希望被点击那一行都显色 3、实现偶数列显色 4、在点击之后&#xff0c;希望被点击单元格的那一列都显色&#xff08;这里随机点的第三列&#xff09;&#xff08;实则下标为2&#xff09; 二、分析 要实现跨行显示…

java使用poi读取跨行跨列excel

java使用poi读取跨行跨列excel 1.需求背景2.实现思路分析3.重要代码片码说明4.完整的代码类如下&#xff1a;5.完整的demo代码提供如下6.demo执行结果 1.需求背景 最近有一个工作任务是用户提供了一个基础的excel文件&#xff0c;要求首先将excel中的数据解析并入库&#xff0c…

itextpdf 表格跨行跨列与可视化图表

文章目录 itextpdf 表格跨行跨列与可视化图表效果图普通表格一&#xff08;表头背景色)普通表格二 &#xff08;隔列变色)表格跨行跨列可视化图表 使用示例普通表格一&#xff08;表头背景色&#xff09;普通表格二 &#xff08;隔列变色&#xff09;表格跨行跨列可视化图表 工…

EasyUI Datagrid跨行跨列的需求

常规开发后台管理系统中遇到的列表查询&#xff0c;都是用到最基本的数据网格&#xff0c;不包括单元格合并&#xff0c;多列页眉&#xff0c;冻结列和页脚等需求。类似如下这个列表 实现也很简单&#xff0c;引入相关的js、css文件&#xff0c;html标签定义展示的列&#xff0…

html布局 跨行,3种方案实现跨行或跨列布局

今天要讲解的这个问题是之前一位小伙伴在群里请教的提问,是关于跨行跨列的布局,如下图是他要实现的具体布局,看似是最简单的二维布局,实际透露出整个CSS的发展方向。向前可以考察对兼容性的处理功底,向后可以考察对CSS新特性的洞察能力。可攻可受,攻守兼备。 如果对此问题…

HTML表格属性跨列,HTML表格的使用 与 跨行跨列

表格的基本语法&#xff1a; 第一个单元格的内容第二个单元格的内容第一个单元格的内容第二个单元格的内容 创建表格一般分为下面四个步骤 1.创建表格标签table 2.在表格标签table创建行标签tr可以有多行 3.在第一行标签tr里创建单元格标签th可以创建表格标题 4.在行标签tr里创…

EXCEL 跨列居中

居中到箭头所指的位置。 先选中三个单元格&#xff0c;打开格式&#xff0c;找到对齐里的跨列居中就行。 结果&#xff1a;

redis数据结构应用

介绍redis数据结构应用场景