取出 SQlite 数据库 Android 设备

我找遍了所有地方,但是我找不到一个真正精确的答案或者一个教程,如果可能的话,怎么做到这一点。

有没有可能以任何方式拉一个 Android 设备的数据库而不需要根?我只是需要提取数据,以任何方式,以便收集它在我的电脑上,所以我该如何执行这一点?我是不是要重新编程,或者你们知道的什么方法,但是记住不要根植设备。谢谢

120692 次浏览
 > is it possible to pull in any way a database of an Android device without having to root it?

yes if your android app creates a file copy of the database that is accessable by everyone.

android protects apps private data so it is not visible/accessable by other apps. a database is private data. your app can of course read the database-file so it can do a file-copy to some public visible file.

A common way to achieve what you desire is to use the ADB pull command.

Another way I prefer in most cases is to copy the database by code to SD card:

try {
File sd = Environment.getExternalStorageDirectory();


if (sd.canWrite()) {
String currentDBPath = "/data/data/" + getPackageName() + "/databases/yourdatabasename";
String backupDBPath = "backupname.db";
File currentDB = new File(currentDBPath);
File backupDB = new File(sd, backupDBPath);


if (currentDB.exists()) {
FileChannel src = new FileInputStream(currentDB).getChannel();
FileChannel dst = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
}
}
} catch (Exception e) {


}

Don't forget to set the permission to write on SD in your manifest, like below.

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

If you want your database file

See the DDMS > File explore

find your db file from your package name

then Click on pull a file from device (Rooted device only)

On a rooted device you can:

// check that db is there
>adb shell
# ls /data/data/app.package.name/databases
db_name.sqlite // a custom named db
# exit
// pull it
>adb pull /data/app.package.name/databases/db_name.sqlite

If your device is running Android v4 or above, you can pull app data, including it's database, without root by using adb backup command, then extract the backup file and access the sqlite database.

First backup app data to your PC via USB cable with the following command, replace app.package.name with the actual package name of the application.

adb backup -f ~/data.ab -noapk app.package.name

This will prompt you to "unlock your device and confirm the backup operation". Do not provide a password for backup encryption, so you can extract it later. Click on the "Back up my data" button on your device. The screen will display the name of the package you're backing up, then close by itself upon successful completion.

The resulting data.ab file in your home folder contains application data in android backup format. To extract it use the following command:

dd if=data.ab bs=1 skip=24 | openssl zlib -d | tar -xvf -

If the above ended with openssl:Error: 'zlib' is an invalid command. error, try the below.

dd if=data.ab bs=1 skip=24 | python -c "import zlib,sys;sys.stdout.write(zlib.decompress(sys.stdin.read()))" | tar -xvf -

The result is the apps/app.package.name/ folder containing application data, including sqlite database.

For more details you can check the original blog post.

For debuggable apps1 on non-rooted devices, you could use following command:

adb shell run-as package.name chmod 666 /data/data/package.name/databases/file
adb pull /data/data/package.name/databases/file

Example:

adb shell run-as com.app chmod 666 /data/data/com.app/databases/data.db
adb pull /data/data/com.app/databases/data.db

Set PATH adb for Enviroment Variables or use cd command to android sdk folder platform-tools.

Example:

cd /folder/android-sdk/platform-tools/

then use above command


1 Note that most apps in Play store are not debuggable since it requires setting the debuggable flag in the manifest.

For Ubuntu (not only?):

see Sergeis Answer but instead of openssl use zlib-flate:

cat appbackup.ab | (dd bs=24 count=0 skip=1; cat) | zlib-flate -uncompress > appbackup.tar

Otherwise openssl will probably throw:

openssl:Error: 'zlib' is an invalid command.

because openssl is not compiled with zlib support in Ubuntu

Since, nothing really work for me. I create a little windows BATCH script based on other answers combined together. Hope it help somebody. Simply usage: backupDatabase < PackageName > < ApplicationName > [TargetDirectory]. It use Sergei's backup method and Android Backup Extractor.

@echo off


if [%1]==[] goto usage
if [%2]==[] goto usage
if NOT [%4]==[] goto usage


@echo Processing: preparations
set PACKAGE=%1
set APPLICATION_NAME=%2
set TARGET_DIR=%cd%
IF NOT "%~3"=="" set TARGET_DIR=%3


set PATH_ADB="c:\Program Files (x86)\Android\android-studio\sdk\platform-tools"
set PATH_ABE="c:\Programs\android-backup-extractor-20140630-bin"
set PATH_7Z="c:\Program Files\7-Zip"


@echo Processing: backup
%PATH_ADB%\adb.exe backup -f %TARGET_DIR%\%APPLICATION_NAME%\%APPLICATION_NAME%.ab -noapk %PACKAGE%


@echo Processing: unpack
java -jar %PATH_ABE%\abe.jar unpack %TARGET_DIR%\%APPLICATION_NAME%\%APPLICATION_NAME%.ab %TARGET_DIR%\%APPLICATION_NAME%\%APPLICATION_NAME%.ab.tar


@echo Processing: extract
cd %TARGET_DIR%\%APPLICATION_NAME%
%PATH_7Z%\7z.exe e %APPLICATION_NAME%.ab.tar "apps\%PACKAGE%\db\%APPLICATION_NAME%"


@echo Processing: cleaning
del %APPLICATION_NAME%.ab
del %APPLICATION_NAME%.ab.tar
goto :eof


:usage
@echo.Pull out SQLite database file from your android device.
@echo.Needs: - connected device
@echo.       - device enable backup.
@echo.       - application enable backup
@echo.       - application in debug mode
@echo.       - installed Android Backup Extractor
@echo.       - installed command line TAR extractor (7z, ...)
@echo.Does NOT need: root device
@echo.
@echo.Uses: - ADB backup (set PATH_ADB)
@echo.      - Android Backup Extractor (http://sourceforge.net/projects/adbextractor/) (set PATH_ABE)
@echo.      - Extract TAR container, uses 7z (set PATH_7Z)
@echo.
@echo.Usage: backupDatabase ^<PackageName^> ^<ApplicationName^> [TargetDirectory]
@echo.Example: backupDatabase com.foo.example ExampleApp
@echo Example: backupDatabase com.foo.example ExampleApp workspace\AndroidProjects\Example
exit /B 1

Based on the answer given by Lam Vinh, here is a simple batch file that works for me on my 1st gen Nexus 7. It prompts the user to enter the package name and then the database name (without the .sqlite extension) and puts it in c:\temp. This assumes you have the Android sdk set in the environment variables.

@echo off
cd c:\temp\


set /p UserInputPackage= Enter the package name:
set /p UserInputDB= Enter the database name:


@echo on
adb shell "run-as %UserInputPackage% chmod 666 /data/data/%UserInputPackage%/databases/%UserInputDB%.sqlite"
adb pull /data/data/%UserInputPackage%/databases/%UserInputDB%.sqlite
@echo off
pause

If you are on Android 4.0 or above, and you are on a mac, then here is a ruby script that will save your app contents to the desktop. I would imagine this would also work in Ubuntu, though I didn't test it.

puts "enter your package name"
package_name = gets.chomp
puts "press the 'Back up my data' button on your device"
`adb backup -f ~/Desktop/data.ab -noapk #{package_name}`
puts "press enter once once the 'Backup finished' toast has appeared"
gets.chomp
puts "extracting..."
`dd if=data.ab bs=1 skip=24 | openssl zlib -d | tar -xvf -`

to run -> ruby your_ruby_file_name.rb

This script is "happy path" only, so please make sure your device is connected and that adb has been added to your profile.

you can easily extract the sqlite file from your device(root no necessary)

  1. Go to SDK Folder
  2. cd platform-tools
  3. start adb

    cd /sdk/platform-tools ./adb shell

    Then type in the following command in terminal

    ./adb -d shell "run-as com.your_packagename cat /data/data/com.your_packagename/databases/jokhanaNepal > /sdcard/jokhana.sqlite"

    For eg

    ./adb -d shell "run-as com.yuvii.app cat /data/data/com.yuvii.app/databases/jokhanaNepal > /sdcard/jokhana.sqlite"

Most of the answers here are way more complicated than they have to be. If you just want to copy the database of your app from your phone to your computer then you just need this command:

adb -d shell "run-as your.package.name cat databases/database.name" > target.sqlite

All you need to fill in in the above command is the package name of your app, what the database is called and optionally what/where you want the database to be copied to.

Please note that this specific command will only work if you have only one device connected to your computer. The -d parameter means that the only connected device will be targeted. But there are other parameters which you can use instead:

  • -e will target the only running emulator
  • -s <serialnumber> will target a device with a specific serial number.

If you are trying to do it on android 6 request the permission and use the code of the answer of this question

if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSION_RC);
return;
}

Once it is granted

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == STORAGE_PERMISSION_RC) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//permission granted  start reading or writing database
} else {
Toast.makeText(this, "No permission to read external storage.", Toast.LENGTH_SHORT).show();
}
}
}

Alternatively you can use my library Ultra Debugger. It's allow to download database as file or edit values directly in browser. No root needed, very easy to use.

 adb shell "run-as [package.name] chmod -R 777 /data/data/[package.name]/databases"
adb shell "mkdir -p /sdcard/tempDB"
adb shell "cp -r /data/data/[package.name]/databases/ /sdcard/tempDB/."
adb pull sdcard/tempDB/ .
adb shell "rm -r /sdcard/tempDB/*"

I give the complete solution to "save" and "restore" the app database to/from the internal storage (not to the PC with adb).

I have done two methods one for save and other for restore the database. Use these methods at the end of the onCreate() in MainActivity (one or the other if you want to saver or restore the database).

save database to internal storage:

void copyDatabase (){
try {
final String inFileName = "/data/data/<pakage.name>/databases/database.db";
final String outFileName = Environment.getExternalStorageDirectory() + "database_backup.db";
File dbFile = new File(inFileName);
FileInputStream fis = new FileInputStream(dbFile);




Log.d(TAG, "copyDatabase: outFile = " + outFileName);


// Open the empty db as the output stream
OutputStream output = new FileOutputStream(outFileName);


// Transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) > 0) {
output.write(buffer, 0, length);
}


// Close the streams
output.flush();
output.close();
fis.close();
}catch (Exception e){
Log.d(TAG, "copyDatabase: backup error");
}
}

restore database from internal storage:

void restoreDatabase (){
try {
final String inFileName = Environment.getExternalStorageDirectory() + "database_backup.db";
final String outFileName = "/data/data/<package.name>/databases/database.db";
File dbFile = new File(inFileName);
FileInputStream fis = new FileInputStream(dbFile);


Log.d(TAG, "copyDatabase: outFile = " + outFileName);


// Open the empty db as the output stream
OutputStream output = new FileOutputStream(outFileName);


// Transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) > 0) {
output.write(buffer, 0, length);
}


// Close the streams
output.flush();
output.close();
fis.close();
}catch (Exception e){
Log.d(TAG, "copyDatabase: backup error");
}
}

Using Android Studio 3.0 or later version it is possible to pull database (also shared preference, cache directory and others) if application runs in debug mode on non-rooted device.

To pull database using android studio follow these steps.

  1. Click View > Tool Windows > Device File Explorer.
  2. Expand /data/data/[package-name] nodes.

Steps followed in Android Studio 3.0

On Mac (NO root required)

1. Go to platform-tools folder.
2) Run following command in terminal.


./adb -d shell "run-as your.package.name cat databases/database.sqlite" > database.sqlite

It will copy the sqlite file in platform-tools folder.

It is always better if things are automated.That's why I wrote simple python script for copying db file from device using ADB. It saves a lot of development time if you're doing it frequently.

Works only with debuggable apps if device is Not rooted.

Here is link to the gist.

Run it as : python copyandroiddbfile.py

import sys
import subprocess
import re


#/
# Created by @nieldeokar on 25/05/2018.
#/


# 1. Python script which will copy database file of debuggable apps from the android device to your computer using ADB.
# 2. This script ask for PackageName and DatabaseName at runtime.
# 3. You can make it static by passing -d at as command line argument while running script and setting defaults in following way.
# 4. Edit script and change the values of varialbe packageName and dbName to debuggable app package name and database name then
# run script as : python Copydbfileandroid.py -d


useDefaults = False




def checkIfPackageInstalled(strSelectedDevice) :


packageName = 'com.nileshdeokar.healthapp.debug'
dbName = 'healthapp.db'




if not useDefaults :
print('Please enter package name : ')
packageName = raw_input()


packageString = 'package:'+packageName


try:
adbCheckIfPackageInstalledOutput = subprocess.check_output('adb -s ' + strSelectedDevice + ' shell pm list packages | grep -x '+ packageString, shell=True)
except subprocess.CalledProcessError as e:
print "Package not found"
return




if packageString.strip() == adbCheckIfPackageInstalledOutput.strip() :
if not useDefaults :
print('Please enter db name : ')
dbName = raw_input()


adbCopyDbString = 'adb -s '+strSelectedDevice + ' -d shell \"run-as '+packageName+' cat /data/data/'+packageName+'/databases/'+ dbName +'\" > '+dbName


try:
copyDbOp = subprocess.check_output(adbCopyDbString,shell=True)
except subprocess.CalledProcessError as e:
return


if "is not debuggable" in copyDbOp :
print packageString + 'is nto debuggable'


if copyDbOp.strip() == "":
print 'Successfully copied '+dbName + ' in current directory'


else :
print 'Package is not installed on the device'






defaultString = "-d"
if len(sys.argv[1:]) > 0 and sys.argv[1] == defaultString :
useDefaults = True


listDevicesOutput = subprocess.check_output("adb devices", shell=True)
listDevicesOutput = listDevicesOutput.replace("List of devices attached"," ").replace("\n","").replace("\t","").replace("\n\n","")


numberofDevices = len(re.findall(r'device+', listDevicesOutput))


connectedDevicesArray = listDevicesOutput.split("device")
del connectedDevicesArray[-1]




strSelectedDevice = ''
if(numberofDevices > 1) :
print('Please select the device : \n'),


for idx, device in enumerate(connectedDevicesArray):
print idx+1,device


selectedDevice = raw_input()


if selectedDevice.isdigit() :
intSelected = int(selectedDevice)
if 1 <= intSelected <= len(connectedDevicesArray) :
print 'Selected device is : ',connectedDevicesArray[intSelected-1]
checkIfPackageInstalled(connectedDevicesArray[intSelected-1])
else :
print 'Please select in range'
else :
print 'Not valid input'


elif numberofDevices == 1 :
checkIfPackageInstalled(connectedDevicesArray[0])
elif numberofDevices == 0 :
print("No device is attached")