Skip to content

Commit 4d2b5eb

Browse files
committed
添加data备份
1 parent ab18499 commit 4d2b5eb

File tree

6 files changed

+261
-10
lines changed

6 files changed

+261
-10
lines changed

app/src/main/java/com/wrbug/developerhelper/ui/widget/appsettingview/AppSettingView.kt

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@ import com.wrbug.developerhelper.mmkv.manager.MMKVManager
1717
import kotlinx.android.synthetic.main.view_app_setting.view.*
1818
import android.content.Intent
1919
import android.net.Uri
20+
import android.os.Environment
2021
import com.wrbug.developerhelper.basecommon.BaseActivity
22+
import com.wrbug.developerhelper.commonutil.zip
2123
import com.wrbug.developerhelper.util.BackupUtils
22-
import com.wrbug.developerhelper.util.DeviceUtils
24+
import com.wrbug.developerhelper.util.toUri
2325
import gdut.bsx.share2.Share2
2426
import gdut.bsx.share2.ShareContentType
27+
import java.io.File
2528

2629

2730
class AppSettingView : ScrollView {
@@ -70,7 +73,7 @@ class AppSettingView : ScrollView {
7073
}
7174

7275
private fun doUninstallApp() {
73-
apkInfo?.run {
76+
apkInfo?.apply {
7477
AppManagerUtils.uninstallApp(context, applicationInfo.packageName)
7578
}
7679
}
@@ -79,7 +82,7 @@ class AppSettingView : ScrollView {
7982
if (checkRoot().not()) {
8083
return
8184
}
82-
apkInfo?.run {
85+
apkInfo?.apply {
8386
showNotice(context.getString(R.string.confirm_delete_app_data), DialogInterface.OnClickListener { _, _ ->
8487
if (AppManagerUtils.clearAppData(applicationInfo.packageName)) {
8588
showToast(context.getString(R.string.clear_complete))
@@ -93,7 +96,7 @@ class AppSettingView : ScrollView {
9396
if (checkRoot().not()) {
9497
return
9598
}
96-
apkInfo?.run {
99+
apkInfo?.apply {
97100
showNotice(context.getString(R.string.confirm_stop_app), DialogInterface.OnClickListener { _, _ ->
98101
AppManagerUtils.forceStopApp(applicationInfo.packageName)
99102
})
@@ -104,7 +107,7 @@ class AppSettingView : ScrollView {
104107
if (checkRoot().not()) {
105108
return
106109
}
107-
apkInfo?.run {
110+
apkInfo?.apply {
108111
showNotice(context.getString(R.string.confirm_restart_app), DialogInterface.OnClickListener { _, _ ->
109112
if (!AppManagerUtils.forceStopApp(applicationInfo.packageName)) {
110113
showToast(context.getString(R.string.restart_failed))
@@ -121,16 +124,52 @@ class AppSettingView : ScrollView {
121124
if (checkRoot().not()) {
122125
return
123126
}
124-
apkInfo?.run {
125-
127+
apkInfo?.apply {
128+
val backupAppData = BackupUtils.backupAppData(applicationInfo.packageName, applicationInfo.dataDir)
129+
if (backupAppData == null) {
130+
showToast(context.getString(R.string.backup_failed))
131+
return
132+
}
133+
if (context !is BaseActivity) {
134+
showToast(context.getString(R.string.backup_success_msg))
135+
return
136+
}
137+
showShareDataNotice(backupAppData)
126138
}
127139
}
128140

141+
private fun showShareDataNotice(backupAppData: File) {
142+
showNotice(
143+
context.getString(R.string.backup_success_and_share_msg),
144+
DialogInterface.OnClickListener { _, _ ->
145+
(context as BaseActivity).requestPermission(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
146+
object : BaseActivity.PermissionCallback() {
147+
override fun granted() {
148+
val zipFile = File(context.externalCacheDir, "${apkInfo?.getAppName() ?: ""}-data.zip")
149+
backupAppData.zip(zipFile)
150+
val uri = zipFile.toUri()
151+
if (uri == null) {
152+
showToast(context.getString(R.string.share_failed))
153+
return
154+
}
155+
Share2.Builder(context as Activity)
156+
.setContentType(ShareContentType.FILE)
157+
.setShareFileUri(uri)
158+
.setOnActivityResult(10)
159+
.build()
160+
.shareBySystem()
161+
}
162+
163+
})
164+
165+
})
166+
}
167+
129168
private fun doBackupApk() {
130169
if (checkRoot().not()) {
131170
return
132171
}
133-
apkInfo?.run {
172+
apkInfo?.apply {
134173
val uri = BackupUtils.backupApk(
135174
applicationInfo.packageName,
136175
applicationInfo.publicSourceDir,
@@ -153,7 +192,10 @@ class AppSettingView : ScrollView {
153192
showNotice(
154193
context.getString(R.string.backup_success_and_share_msg),
155194
DialogInterface.OnClickListener { _, _ ->
156-
(context as BaseActivity).requestPermission(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
195+
(context as BaseActivity).requestPermission(arrayOf(
196+
Manifest.permission.READ_EXTERNAL_STORAGE,
197+
Manifest.permission.WRITE_EXTERNAL_STORAGE
198+
),
157199
object : BaseActivity.PermissionCallback() {
158200
override fun granted() {
159201
Share2.Builder(context as Activity)

app/src/main/java/com/wrbug/developerhelper/util/BackupUtils.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.wrbug.developerhelper.util
33
import android.net.Uri
44
import android.os.Environment
55
import com.wrbug.developerhelper.commonutil.shell.ShellManager
6+
import com.wrbug.developerhelper.commonutil.zip
67
import java.io.File
78

89
object BackupUtils {
@@ -21,4 +22,13 @@ object BackupUtils {
2122
}
2223
return null
2324
}
25+
26+
fun backupAppData(packageName: String, dataDir: String): File? {
27+
val backupDataDir =
28+
File(backupDir, "datas/$packageName/${System.currentTimeMillis().format("yyyy-MM-dd-HH_mm_ss")}")
29+
if (ShellManager.cpFile(dataDir, backupDataDir.absolutePath)) {
30+
return backupDataDir
31+
}
32+
return null
33+
}
2434
}

app/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,5 @@
7373
<string name="backup_success_msg">备份成功,文件已备份到内部存储下com.wrbug.developerHelper目录中</string>
7474
<string name="backup_failed">备份失败</string>
7575
<string name="backup_success_and_share_msg">备份成功,文件已备份到内部存储下com.wrbug.developerHelper目录中,是否立即分享给好友?</string>
76+
<string name="share_failed">分享失败</string>
7677
</resources>

app/src/main/res/xml/filepaths.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@
33
<external-path
44
name="file"
55
path="com.wrbug.developerHelper" />
6+
<external-cache-path
7+
name="ext_cache"
8+
path="/" />
69
</paths>
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
package com.wrbug.developerhelper.commonutil
2+
3+
import java.io.*
4+
import java.util.zip.ZipEntry
5+
import java.util.zip.ZipFile
6+
import java.util.zip.ZipOutputStream
7+
8+
object ZipUtils {
9+
fun zip(src: File, outFile: File) {
10+
//提供了一个数据项压缩成一个ZIP归档输出流
11+
var out: ZipOutputStream? = null
12+
try {
13+
out = ZipOutputStream(FileOutputStream(outFile))
14+
//如果此文件是一个文件,否则为false。
15+
if (src.isFile) {
16+
zipFileOrDirectory(out, src, "")
17+
} else {
18+
//返回一个文件或空阵列。
19+
val entries = src.listFiles()
20+
for (i in entries!!.indices) {
21+
// 递归压缩,更新curPaths
22+
zipFileOrDirectory(out, entries[i], "")
23+
}
24+
}
25+
} catch (ex: IOException) {
26+
ex.printStackTrace()
27+
} finally {
28+
//关闭输出流
29+
if (out != null) {
30+
try {
31+
out.close()
32+
} catch (ex: IOException) {
33+
ex.printStackTrace()
34+
}
35+
36+
}
37+
}
38+
}
39+
40+
fun zip(src: File): File? {
41+
val outFile = File(src.parent, src.name + ".zip")//源文件或者目录
42+
zip(src, outFile)
43+
return outFile
44+
}
45+
46+
@Throws(IOException::class)
47+
private fun zipFileOrDirectory(
48+
out: ZipOutputStream,
49+
fileOrDirectory: File, curPath: String
50+
) {
51+
//从文件中读取字节的输入流
52+
var fileInputStream: FileInputStream? = null
53+
try {
54+
//如果此文件是一个目录,否则返回false。
55+
if (!fileOrDirectory.isDirectory) {
56+
// 压缩文件
57+
val buffer = ByteArray(4096)
58+
fileInputStream = FileInputStream(fileOrDirectory)
59+
//实例代表一个条目内的ZIP归档
60+
val entry = ZipEntry(curPath + fileOrDirectory.name)
61+
//条目的信息写入底层流
62+
out.putNextEntry(entry)
63+
var bytesRead: Int = fileInputStream.read(buffer)
64+
while (bytesRead != -1) {
65+
out.write(buffer, 0, bytesRead)
66+
bytesRead = fileInputStream.read(buffer)
67+
}
68+
out.closeEntry()
69+
} else {
70+
// 压缩目录
71+
val entries = fileOrDirectory.listFiles()
72+
for (i in entries!!.indices) {
73+
// 递归压缩,更新curPaths
74+
zipFileOrDirectory(
75+
out, entries[i], curPath
76+
+ fileOrDirectory.name + "/"
77+
)
78+
}
79+
}
80+
} catch (ex: IOException) {
81+
ex.printStackTrace()
82+
// throw ex;
83+
} finally {
84+
if (fileInputStream != null) {
85+
try {
86+
fileInputStream.close()
87+
} catch (ex: IOException) {
88+
ex.printStackTrace()
89+
}
90+
91+
}
92+
}
93+
}
94+
95+
@Throws(IOException::class)
96+
fun unzip(zipFileName: String, outputDirectory: String) {
97+
var zipFile: ZipFile? = null
98+
try {
99+
zipFile = ZipFile(zipFileName)
100+
val e = zipFile.entries()
101+
var zipEntry: ZipEntry? = null
102+
val dest = File(outputDirectory)
103+
dest.mkdirs()
104+
while (e.hasMoreElements()) {
105+
zipEntry = e.nextElement() as ZipEntry
106+
val entryName = zipEntry.name
107+
var inputStream: InputStream? = null
108+
var out: FileOutputStream? = null
109+
try {
110+
if (zipEntry.isDirectory) {
111+
var name = zipEntry.name
112+
name = name.substring(0, name.length - 1)
113+
val f = File(
114+
outputDirectory + File.separator
115+
+ name
116+
)
117+
f.mkdirs()
118+
} else {
119+
var index = entryName.lastIndexOf("\\")
120+
if (index != -1) {
121+
val df = File(
122+
outputDirectory + File.separator
123+
+ entryName.substring(0, index)
124+
)
125+
df.mkdirs()
126+
}
127+
index = entryName.lastIndexOf("/")
128+
if (index != -1) {
129+
val df = File(
130+
outputDirectory + File.separator
131+
+ entryName.substring(0, index)
132+
)
133+
df.mkdirs()
134+
}
135+
val f = File(
136+
outputDirectory + File.separator
137+
+ zipEntry.name
138+
)
139+
// f.createNewFile();
140+
inputStream = zipFile.getInputStream(zipEntry)
141+
out = FileOutputStream(f)
142+
val by = ByteArray(1024)
143+
var c: Int = inputStream?.read(by) ?: -1
144+
while (c != -1) {
145+
out.write(by, 0, c)
146+
c = inputStream?.read(by) ?: -1
147+
}
148+
out.flush()
149+
}
150+
} catch (ex: IOException) {
151+
ex.printStackTrace()
152+
throw IOException("解压失败:" + ex.toString())
153+
} finally {
154+
if (inputStream != null) {
155+
try {
156+
inputStream.close()
157+
} catch (ex: IOException) {
158+
}
159+
160+
}
161+
if (out != null) {
162+
try {
163+
out.close()
164+
} catch (ex: IOException) {
165+
}
166+
167+
}
168+
}
169+
}
170+
} catch (ex: IOException) {
171+
ex.printStackTrace()
172+
throw IOException("解压失败:" + ex.toString())
173+
} finally {
174+
if (zipFile != null) {
175+
try {
176+
zipFile.close()
177+
} catch (ex: IOException) {
178+
}
179+
180+
}
181+
}
182+
}
183+
}
184+
185+
186+
fun File.zip(): File? {
187+
return ZipUtils.zip(this)
188+
}
189+
190+
191+
fun File.zip(outFile: File) {
192+
return ZipUtils.zip(this, outFile)
193+
}

commonutil/src/main/java/com/wrbug/developerhelper/commonutil/shell/ShellManager.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,9 @@ object ShellManager {
214214
if (commandResult.isSuccessful.not()) {
215215
return false
216216
}
217-
commandResult = ShellUtils.runWithSu("cp $source $dst && chmod $mod $dst")
217+
commandResult = ShellUtils.runWithSu("cp -R $source $dst && chmod $mod $dst")
218+
if (commandResult.isSuccessful.not()) {
219+
}
218220
return commandResult.isSuccessful
219221
}
220222

0 commit comments

Comments
 (0)