1.使用自定义的文件选择器来选择本地文件

2.修复自定义储存目录的相关Bug
3.英文支持
pull/10/head
kai-city 4 years ago
parent 87217696dd
commit 34627566d6
  1. 3
      app/build.gradle
  2. 2
      app/src/main/java/top/niunaijun/blackdex/app/App.kt
  3. 4
      app/src/main/java/top/niunaijun/blackdex/app/BlackDexLoader.kt
  4. 21
      app/src/main/java/top/niunaijun/blackdex/data/DexDumpRepository.kt
  5. 16
      app/src/main/java/top/niunaijun/blackdex/util/FileUtil.kt
  6. 11
      app/src/main/java/top/niunaijun/blackdex/view/base/BaseActivity.kt
  7. 99
      app/src/main/java/top/niunaijun/blackdex/view/base/PermissionActivity.kt
  8. 108
      app/src/main/java/top/niunaijun/blackdex/view/main/MainActivity.kt
  9. 8
      app/src/main/java/top/niunaijun/blackdex/view/setting/SettingActivity.kt
  10. 32
      app/src/main/java/top/niunaijun/blackdex/view/setting/SettingFragment.kt
  11. 26
      app/src/main/res/values-zh/string.xml
  12. 29
      app/src/main/res/values/strings.xml
  13. 6
      app/src/main/res/xml/setting.xml
  14. 4
      build.gradle

@ -96,6 +96,9 @@ dependencies {
implementation 'com.github.Ferfalk:SimpleSearchView:0.2.0' implementation 'com.github.Ferfalk:SimpleSearchView:0.2.0'
//searchView //searchView
implementation 'com.umeng.umsdk:common:9.3.8'
implementation 'com.umeng.umsdk:asms:1.2.2'
//
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.ext:junit:1.1.2'

@ -3,6 +3,7 @@ package top.niunaijun.blackboxa.app
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
import com.umeng.commonsdk.UMConfigure
import top.niunaijun.blackdex.app.AppManager import top.niunaijun.blackdex.app.AppManager
/** /**
@ -28,6 +29,7 @@ class App : Application() {
override fun attachBaseContext(base: Context?) { override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base) super.attachBaseContext(base)
mContext = base!! mContext = base!!
UMConfigure.init(base, "60b373136c421a3d97d23c29", "Github", 0, "")
AppManager.doAttachBaseContext(base) AppManager.doAttachBaseContext(base)
} }

@ -20,7 +20,7 @@ class BlackDexLoader {
private var mSavePath by AppSharedPreferenceDelegate(App.getContext(), "") private var mSavePath by AppSharedPreferenceDelegate(App.getContext(), "")
private var mSaveEnable by AppSharedPreferenceDelegate(App.getContext(), false) private var mSaveEnable by AppSharedPreferenceDelegate(App.getContext(), true)
private var mDir = if (mSaveEnable) { private var mDir = if (mSaveEnable) {
getDexDumpDir(App.getContext()) getDexDumpDir(App.getContext())
@ -73,7 +73,7 @@ class BlackDexLoader {
return if (BuildCompat.isR()) { return if (BuildCompat.isR()) {
val dump = File( val dump = File(
context.externalCacheDir?.parentFile?.parentFile?.parentFile?.parentFile, context.externalCacheDir?.parentFile?.parentFile?.parentFile?.parentFile,
"hupu/dexDump" "Download/dexDump"
) )
FileUtils.mkdirs(dump) FileUtils.mkdirs(dump)
dump.absolutePath dump.absolutePath

@ -28,7 +28,8 @@ class DexDumpRepository {
fun getAppList(mAppListLiveData: MutableLiveData<List<AppInfo>>) { fun getAppList(mAppListLiveData: MutableLiveData<List<AppInfo>>) {
val installedApplications: List<ApplicationInfo> = getPackageManager().getInstalledApplications(0) val installedApplications: List<ApplicationInfo> =
getPackageManager().getInstalledApplications(0)
val installedList = mutableListOf<AppInfo>() val installedList = mutableListOf<AppInfo>()
for (installedApplication in installedApplications) { for (installedApplication in installedApplications) {
@ -40,9 +41,9 @@ class DexDumpRepository {
val info = AppInfo( val info = AppInfo(
installedApplication.loadLabel(getPackageManager()).toString(), installedApplication.loadLabel(getPackageManager()).toString(),
installedApplication.packageName, installedApplication.packageName,
installedApplication.loadIcon(getPackageManager()) installedApplication.loadIcon(getPackageManager())
) )
installedList.add(info) installedList.add(info)
} }
@ -56,30 +57,32 @@ class DexDumpRepository {
val result = if (URLUtil.isValidUrl(source)) { val result = if (URLUtil.isValidUrl(source)) {
BlackDexCore.get().dumpDex(Uri.parse(source)) BlackDexCore.get().dumpDex(Uri.parse(source))
} else if (source.contains("/")) {
BlackDexCore.get().dumpDex(File(source))
} else { } else {
BlackDexCore.get().dumpDex(source) BlackDexCore.get().dumpDex(source)
} }
if(result){ if (result) {
dumpTaskId++ dumpTaskId++
startCountdown(dexDumpLiveData) startCountdown(dexDumpLiveData)
}else{ } else {
dexDumpLiveData.postValue(DumpInfo(DumpInfo.TIMEOUT)) dexDumpLiveData.postValue(DumpInfo(DumpInfo.TIMEOUT))
} }
} }
fun dumpSuccess(){ fun dumpSuccess() {
dumpTaskId++ dumpTaskId++
} }
private fun startCountdown(dexDumpLiveData: MutableLiveData<DumpInfo>){ private fun startCountdown(dexDumpLiveData: MutableLiveData<DumpInfo>) {
GlobalScope.launch { GlobalScope.launch {
val tempId = dumpTaskId val tempId = dumpTaskId
delay(10000) delay(10000)
if(tempId == dumpTaskId){ if (tempId == dumpTaskId) {
dexDumpLiveData.postValue(DumpInfo(DumpInfo.TIMEOUT)) dexDumpLiveData.postValue(DumpInfo(DumpInfo.TIMEOUT))
} }
} }

@ -0,0 +1,16 @@
package top.niunaijun.blackdex.util
import java.io.File
/**
*
* @Description: file util
* @Author: wukaicheng
* @CreateDate: 2021/5/30 20:25
*/
object FileUtil {
fun filterApk(file: File):Boolean{
return (file.extension == "apk") or file.isDirectory
}
}

@ -11,7 +11,12 @@ import androidx.appcompat.widget.Toolbar
*/ */
open class BaseActivity : AppCompatActivity() { open class BaseActivity : AppCompatActivity() {
protected fun initToolbar(toolbar: Toolbar,title:Int, showBack: Boolean = false, onBack: (() -> Unit)? = null) { protected fun initToolbar(
toolbar: Toolbar,
title: Int,
showBack: Boolean = false,
onBack: (() -> Unit)? = null
) {
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
toolbar.setTitle(title) toolbar.setTitle(title)
if (showBack) { if (showBack) {
@ -20,11 +25,13 @@ open class BaseActivity : AppCompatActivity() {
toolbar.setNavigationOnClickListener { toolbar.setNavigationOnClickListener {
if (onBack != null) { if (onBack != null) {
onBack() onBack()
}else{ } else {
finish() finish()
} }
} }
} }
} }
} }
} }

@ -0,0 +1,99 @@
package top.niunaijun.blackdex.view.base
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.Settings
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import com.afollestad.materialdialogs.MaterialDialog
import top.niunaijun.blackbox.utils.compat.BuildCompat
import top.niunaijun.blackdex.R
/**
*
* @Description:request permission activity
* @Author: wukaicheng
* @CreateDate: 2021/5/30 21:27
*/
open class PermissionActivity:BaseActivity() {
protected var requestPermissionCallback: ((Boolean) -> Unit)? = null
protected fun requestStoragePermission() {
@RequiresApi(Build.VERSION_CODES.R)
if (BuildCompat.isR()) {
if (Environment.isExternalStorageManager()) {
//fuck 请求了读取全部文件权限竟然还要申请普通读写权限
requestPermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
} else {
MaterialDialog(this).show {
title(R.string.grant_permission)
message(res = R.string.request_storage_msg)
negativeButton(res = R.string.request_later) {
if(requestPermissionCallback!=null){
requestPermissionCallback!!(false)
}
}
positiveButton(res = R.string.jump_grant) {
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
intent.data = Uri.fromParts("package", packageName, null)
startActivity(intent)
}
}
}
} else if (BuildCompat.isM() && checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
requestPermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}else{
if(requestPermissionCallback!=null){
requestPermissionCallback!!(true)
}
}
}
@RequiresApi(Build.VERSION_CODES.M)
private val requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
if (it) {
if(requestPermissionCallback!=null){
requestPermissionCallback!!(true)
}
} else {
MaterialDialog(this).show {
title(res = R.string.request_fail)
message(res = R.string.denied_msg)
if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
positiveButton(res = R.string.request_again) {
requestStoragePermission()
}
} else {
positiveButton(res = R.string.jump_grant) {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
val uri = Uri.fromParts("package", packageName, null)
intent.data = uri
startActivity(intent)
}
}
negativeButton(res = R.string.request_later) {
if(requestPermissionCallback!=null){
requestPermissionCallback!!(false)
}
}
}
}
}
override fun onStart() {
super.onStart()
if(requestPermissionCallback!=null){
requestStoragePermission()
}
}
}

@ -1,38 +1,35 @@
package top.niunaijun.blackdex.view.main package top.niunaijun.blackdex.view.main
import android.Manifest
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.provider.Settings import android.os.Environment
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.files.fileChooser
import com.ferfalk.simplesearchview.SimpleSearchView import com.ferfalk.simplesearchview.SimpleSearchView
import com.roger.catloadinglibrary.CatLoadingView import com.roger.catloadinglibrary.CatLoadingView
import com.umeng.analytics.MobclickAgent
import top.niunaijun.blackbox.BlackDexCore import top.niunaijun.blackbox.BlackDexCore
import top.niunaijun.blackbox.core.system.dump.IBDumpMonitor import top.niunaijun.blackbox.core.system.dump.IBDumpMonitor
import top.niunaijun.blackbox.entity.dump.DumpResult import top.niunaijun.blackbox.entity.dump.DumpResult
import top.niunaijun.blackbox.utils.compat.BuildCompat
import top.niunaijun.blackdex.R import top.niunaijun.blackdex.R
import top.niunaijun.blackdex.data.entity.AppInfo import top.niunaijun.blackdex.data.entity.AppInfo
import top.niunaijun.blackdex.data.entity.DumpInfo import top.niunaijun.blackdex.data.entity.DumpInfo
import top.niunaijun.blackdex.databinding.ActivityMainBinding import top.niunaijun.blackdex.databinding.ActivityMainBinding
import top.niunaijun.blackdex.util.FileUtil
import top.niunaijun.blackdex.util.InjectionUtil import top.niunaijun.blackdex.util.InjectionUtil
import top.niunaijun.blackdex.util.LoadingUtil import top.niunaijun.blackdex.util.LoadingUtil
import top.niunaijun.blackdex.util.inflate import top.niunaijun.blackdex.util.inflate
import top.niunaijun.blackdex.view.base.BaseActivity import top.niunaijun.blackdex.view.base.PermissionActivity
import top.niunaijun.blackdex.view.setting.SettingActivity import top.niunaijun.blackdex.view.setting.SettingActivity
class MainActivity : BaseActivity() { class MainActivity : PermissionActivity() {
private val viewBinding: ActivityMainBinding by inflate() private val viewBinding: ActivityMainBinding by inflate()
@ -72,7 +69,25 @@ class MainActivity : BaseActivity() {
} }
viewBinding.fab.setOnClickListener { viewBinding.fab.setOnClickListener {
openDocumentedResult.launch("application/vnd.android.package-archive") this.requestPermissionCallback = {
if (it) {
this.requestPermissionCallback = null
val initialDir = Environment.getExternalStorageDirectory()
MaterialDialog(this).show {
fileChooser(
this@MainActivity,
initialDirectory = initialDir,
filter = FileUtil::filterApk,
) { _, file ->
viewModel.startDexDump(file.absolutePath)
}
negativeButton(res = R.string.cancel)
}
}
}
requestStoragePermission()
} }
} }
@ -104,31 +119,31 @@ class MainActivity : BaseActivity() {
DumpInfo.TIMEOUT -> { DumpInfo.TIMEOUT -> {
loadingView.dismiss() loadingView.dismiss()
MaterialDialog(this).show { MaterialDialog(this).show {
title(text = "脱壳失败") title(res = R.string.unpack_fail)
message(text = "未知错误,可前往GitHub(https://github.com/CodingGay/BlackDex)提Issue") message(res = R.string.jump_issue)
negativeButton(text = "Github") { negativeButton(res = R.string.github) {
val intent = Intent( val intent = Intent(
Intent.ACTION_VIEW, Intent.ACTION_VIEW,
Uri.parse("https://github.com/CodingGay/BlackDex/issues") Uri.parse("https://github.com/CodingGay/BlackDex/issues")
) )
startActivity(intent) startActivity(intent)
} }
positiveButton(text = "确定") positiveButton(res = R.string.confirm)
} }
} }
else -> { else -> {
viewModel.dexDumpSuccess() viewModel.dexDumpSuccess()
val title = if (it.state == DumpInfo.SUCCESS) { val title = if (it.state == DumpInfo.SUCCESS) {
"脱壳成功" getString(R.string.unpack_success)
} else { } else {
"脱壳失败" getString(R.string.unpack_fail)
} }
loadingView.dismiss() loadingView.dismiss()
MaterialDialog(this).show { MaterialDialog(this).show {
title(text = title) title(text = title)
message(text = it.msg) message(text = it.msg)
positiveButton(text = "确定") positiveButton(res = R.string.confirm)
} }
} }
} }
@ -144,14 +159,14 @@ class MainActivity : BaseActivity() {
viewModel.mDexDumpLiveData.postValue( viewModel.mDexDumpLiveData.postValue(
DumpInfo( DumpInfo(
DumpInfo.SUCCESS, DumpInfo.SUCCESS,
"DEX文件储存在:${result.dir}" getString(R.string.dex_save, result.dir)
) )
) )
} else { } else {
viewModel.mDexDumpLiveData.postValue( viewModel.mDexDumpLiveData.postValue(
DumpInfo( DumpInfo(
DumpInfo.FAIL, DumpInfo.FAIL,
"错误原因: ${result.msg}" getString(R.string.error_msg, result.msg)
) )
) )
} }
@ -202,52 +217,6 @@ class MainActivity : BaseActivity() {
} }
} }
private fun requestStoragePermission() {
if (BuildCompat.isM() && checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
requestPermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
}
private val openDocumentedResult =
registerForActivityResult(ActivityResultContracts.GetContent()) {
it?.run {
viewModel.startDexDump(it.toString())
}
}
@RequiresApi(Build.VERSION_CODES.M)
private val requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
if (!it) {
MaterialDialog(this).show {
title(text = "申请失败")
message(text = "请授予我们读写本地文件权限,否则软件将无法正常运行。")
if (shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
positiveButton(text = "再次申请") {
requestStoragePermission()
}
} else {
positiveButton(text = "手动授予") {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
val uri = Uri.fromParts("package", packageName, null)
intent.data = uri
startActivity(intent)
}
}
negativeButton(text = "退出软件") {
finish()
}
}
}
}
override fun onStart() {
super.onStart()
requestStoragePermission()
}
override fun onBackPressed() { override fun onBackPressed() {
if (viewBinding.searchView.isSearchOpen) { if (viewBinding.searchView.isSearchOpen) {
viewBinding.searchView.closeSearch() viewBinding.searchView.closeSearch()
@ -285,4 +254,13 @@ class MainActivity : BaseActivity() {
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
override fun onResume() {
super.onResume()
MobclickAgent.onResume(this)
}
override fun onPause() {
super.onPause()
MobclickAgent.onPause(this)
}
} }

@ -5,8 +5,9 @@ import top.niunaijun.blackdex.R
import top.niunaijun.blackdex.databinding.ActivitySettingBinding import top.niunaijun.blackdex.databinding.ActivitySettingBinding
import top.niunaijun.blackdex.util.inflate import top.niunaijun.blackdex.util.inflate
import top.niunaijun.blackdex.view.base.BaseActivity import top.niunaijun.blackdex.view.base.BaseActivity
import top.niunaijun.blackdex.view.base.PermissionActivity
class SettingActivity : BaseActivity() { class SettingActivity : PermissionActivity() {
private val viewBinding: ActivitySettingBinding by inflate() private val viewBinding: ActivitySettingBinding by inflate()
@ -16,4 +17,9 @@ class SettingActivity : BaseActivity() {
initToolbar(viewBinding.toolbarLayout.toolbar, R.string.app_setting,true) initToolbar(viewBinding.toolbarLayout.toolbar, R.string.app_setting,true)
supportFragmentManager.beginTransaction().replace(R.id.fragment,SettingFragment()).commit() supportFragmentManager.beginTransaction().replace(R.id.fragment,SettingFragment()).commit()
} }
fun setRequestCallback(callback:((Boolean)->Unit)?){
this.requestPermissionCallback = callback
requestStoragePermission()
}
} }

@ -7,10 +7,13 @@ import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreferenceCompat import androidx.preference.SwitchPreferenceCompat
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.files.folderChooser import com.afollestad.materialdialogs.files.folderChooser
import top.niunaijun.blackboxa.app.App
import top.niunaijun.blackdex.R import top.niunaijun.blackdex.R
import top.niunaijun.blackdex.app.AppManager import top.niunaijun.blackdex.app.AppManager
import top.niunaijun.blackdex.app.BlackDexLoader
import java.io.File import java.io.File
/** /**
* *
* @Description: * @Description:
@ -33,29 +36,52 @@ class SettingFragment : PreferenceFragmentCompat() {
saveEnablePreference = findPreference("save_enable")!! saveEnablePreference = findPreference("save_enable")!!
saveEnablePreference.onPreferenceChangeListener = mSaveEnableChange saveEnablePreference.onPreferenceChangeListener = mSaveEnableChange
saveEnablePreference.isChecked = AppManager.mBlackBoxLoader.saveEnable()
} }
private val mSavedPathClick = Preference.OnPreferenceClickListener { private val mSavedPathClick = Preference.OnPreferenceClickListener {
val initialFile = with(initialDirectory) { val initialFile = with(initialDirectory) {
if (initialDirectory.isEmpty()) { if (initialDirectory.isEmpty()) {
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) Environment.getExternalStorageDirectory()
} else { } else {
File(this) File(this)
} }
} }
MaterialDialog(requireContext()).show { MaterialDialog(requireContext()).show {
folderChooser(requireContext(), initialDirectory = initialFile,allowFolderCreation = true) { _, file -> folderChooser(
requireContext(),
initialDirectory = initialFile,
allowFolderCreation = true
) { _, file ->
AppManager.mBlackBoxLoader.setSavePath(file.absolutePath) AppManager.mBlackBoxLoader.setSavePath(file.absolutePath)
savePathPreference.summary = file.absolutePath savePathPreference.summary = file.absolutePath
} }
negativeButton(res = R.string.cancel)
} }
return@OnPreferenceClickListener true return@OnPreferenceClickListener true
} }
private val mSaveEnableChange = Preference.OnPreferenceChangeListener { _, newValue -> private val mSaveEnableChange = Preference.OnPreferenceChangeListener { _, newValue ->
AppManager.mBlackBoxLoader.saveEnable(newValue as Boolean) if (newValue == false) {
(requireActivity() as SettingActivity).setRequestCallback(requestResult)
} else {
AppManager.mBlackBoxLoader.saveEnable(true)
saveEnablePreference.isChecked = true
}
return@OnPreferenceChangeListener true return@OnPreferenceChangeListener true
} }
private val requestResult = { hasPermission: Boolean ->
AppManager.mBlackBoxLoader.saveEnable(!hasPermission)
saveEnablePreference.isChecked = !hasPermission
if (AppManager.mBlackBoxLoader.getSavePath().isEmpty()) {
val path = BlackDexLoader.getDexDumpDir(App.getContext())
AppManager.mBlackBoxLoader.setSavePath(path)
savePathPreference.summary = path
}
}
} }

@ -0,0 +1,26 @@
<resources>
<string name="filter">过滤</string>
<string name="choose">选择</string>
<string name="log">软件日志</string>
<string name="open_source">开源地址</string>
<string name="app_setting">软件设置</string>
<string name="unpack_success">脱壳成功</string>
<string name="unpack_fail">脱壳失败</string>
<string name="confirm">确定</string>
<string name="github">Github</string>
<string name="jump_issue">未知错误,可前往GitHub(https://github.com/CodingGay/BlackDex)提Issue</string>
<string name="cancel">取消</string>
<string name="dex_save">DEX文件储存在: %1$s</string>
<string name="error_msg">错误原因: %1$s</string>
<string name="grant_permission">授予权限</string>
<string name="request_again">再次申请</string>
<string name="request_later">下次再说</string>
<string name="jump_grant">前往授予</string>
<string name="request_fail">申请失败</string>
<string name="denied_msg">拒绝授予读写本地文件权限将无法使用该功能</string>
<string name="request_storage_msg">该功能需要您授予本软件读写全部文件权限才行正常运行</string>
<string name="file_save">文件储存</string>
<string name="use_default_file">使用默认储存路径</string>
<string name="rewrite_file_path">自定义储存路径</string>
</resources>

@ -1,7 +1,26 @@
<resources> <resources>
<string name="filter">过滤</string> <string name="filter">Filter</string>
<string name="choose">选择</string> <string name="choose">Select</string>
<string name="log">软件日志</string> <string name="log">Logcat</string>
<string name="open_source">开源地址</string> <string name="open_source">Open Source</string>
<string name="app_setting">软件设置</string> <string name="app_setting">Setting</string>
<string name="unpack_success">Unpack Success</string>
<string name="unpack_fail">Unpack Fail</string>
<string name="confirm">Confirm</string>
<string name="github">Github</string>
<string name="jump_issue">Unknown Error,You can jump to GitHub(https://github.com/CodingGay/BlackDex)open Issue</string>
<string name="cancel">Cancel</string>
<string name="dex_save">.dex file save in: %1$s</string>
<string name="error_msg">Error: %1$s</string>
<string name="grant_permission">Grant Permission</string>
<string name="request_again">Again</string>
<string name="request_later">Later</string>
<string name="jump_grant">Grant</string>
<string name="request_fail">Grant Fail</string>
<string name="denied_msg">Denying permission to read and write to local files will disable this feature</string>
<string name="request_storage_msg">This function requires you to grant the software the permission to read and write all files to run normally</string>
<string name="file_save">File</string>
<string name="use_default_file">Use Default Path</string>
<string name="rewrite_file_path">Customize the storage path</string>
</resources> </resources>

@ -1,15 +1,15 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="文件储存"> <PreferenceCategory android:title="@string/file_save">
<SwitchPreferenceCompat <SwitchPreferenceCompat
android:disableDependentsState="true" android:disableDependentsState="true"
android:key="save_enable" android:key="save_enable"
android:title="使用默认储存路径" /> android:title="@string/use_default_file" />
<Preference <Preference
android:dependency="save_enable" android:dependency="save_enable"
android:key="save_path" android:key="save_path"
android:title="自定义储存路径" /> android:title="@string/rewrite_file_path" />
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>

@ -10,7 +10,7 @@ buildscript {
jcenter { url 'https://maven.aliyun.com/repository/jcenter' } jcenter { url 'https://maven.aliyun.com/repository/jcenter' }
jcenter { url 'https://maven.aliyun.com/nexus/content/groups/public/' } jcenter { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'https://maven.aliyun.com/repository/gradle-plugin' } maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
maven { url 'https://dl.bintray.com/umsdk/release' } maven { url 'https://repo1.maven.org/maven2/' }
maven { url 'https://jitpack.io' } maven { url 'https://jitpack.io' }
} }
dependencies { dependencies {
@ -30,7 +30,7 @@ allprojects {
jcenter { url 'https://maven.aliyun.com/repository/jcenter' } jcenter { url 'https://maven.aliyun.com/repository/jcenter' }
jcenter { url 'https://maven.aliyun.com/nexus/content/groups/public/' } jcenter { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'https://maven.aliyun.com/repository/gradle-plugin' } maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
maven { url 'https://dl.bintray.com/umsdk/release' } maven { url 'https://repo1.maven.org/maven2/' }
maven { url 'https://jitpack.io' } maven { url 'https://jitpack.io' }
} }
} }

Loading…
Cancel
Save