Merge pull request #10 from wukaicheng/main

一些新功能
pull/15/head
Milk 4 years ago committed by GitHub
commit 9e49e89e78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      app/build.gradle
  2. 23
      app/src/main/AndroidManifest.xml
  3. 26
      app/src/main/java/top/niunaijun/blackdex/App.kt
  4. 40
      app/src/main/java/top/niunaijun/blackdex/app/App.kt
  5. 26
      app/src/main/java/top/niunaijun/blackdex/app/AppManager.kt
  6. 87
      app/src/main/java/top/niunaijun/blackdex/app/BlackDexLoader.kt
  7. 67
      app/src/main/java/top/niunaijun/blackdex/biz/cache/AppSharedPreferenceDelegate.kt
  8. 41
      app/src/main/java/top/niunaijun/blackdex/data/BlackDexConfiguration.kt
  9. 15
      app/src/main/java/top/niunaijun/blackdex/data/DexDumpRepository.kt
  10. 16
      app/src/main/java/top/niunaijun/blackdex/util/FileUtil.kt
  11. 12
      app/src/main/java/top/niunaijun/blackdex/view/base/BaseActivity.kt
  12. 99
      app/src/main/java/top/niunaijun/blackdex/view/base/PermissionActivity.kt
  13. 127
      app/src/main/java/top/niunaijun/blackdex/view/main/MainActivity.kt
  14. 25
      app/src/main/java/top/niunaijun/blackdex/view/setting/SettingActivity.kt
  15. 87
      app/src/main/java/top/niunaijun/blackdex/view/setting/SettingFragment.kt
  16. 22
      app/src/main/res/layout/activity_setting.xml
  17. 5
      app/src/main/res/menu/menu_main.xml
  18. 26
      app/src/main/res/values-zh/string.xml
  19. 28
      app/src/main/res/values/strings.xml
  20. 15
      app/src/main/res/xml/setting.xml
  21. 4
      build.gradle

@ -11,8 +11,8 @@ android {
applicationId "top.niunaijun.blackdex"
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
versionCode 2
versionName "1.1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@ -72,6 +72,7 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.preference:preference-ktx:1.1.1'
implementation project(':Bcore')
@ -86,6 +87,7 @@ dependencies {
//third
implementation 'com.afollestad.material-dialogs:core:3.3.0'
implementation 'com.afollestad.material-dialogs:files:3.2.1'
//dialog
implementation 'com.github.nukc.stateview:kotlin:2.2.0'
//
@ -94,6 +96,9 @@ dependencies {
implementation 'com.github.Ferfalk:SimpleSearchView:0.2.0'
//searchView
implementation 'com.umeng.umsdk:common:9.3.8'
implementation 'com.umeng.umsdk:asms:1.2.2'
//
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'

@ -4,28 +4,37 @@
package="top.niunaijun.blackdex">
<!-- Android 11 需要 -->
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<application
android:name="top.niunaijun.blackboxa.app.App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:name=".App"
android:requestLegacyExternalStorage="true"
android:supportsRtl="true"
android:theme="@style/Theme.BlackDex">
<activity android:name=".view.base.WelcomeActivity"
<activity
android:name=".view.base.WelcomeActivity"
android:theme="@style/WelcomeTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".view.main.MainActivity">
</activity>
<activity android:name=".view.main.MainActivity" />
<activity android:name=".view.setting.SettingActivity" />
</application>
</manifest>

@ -1,26 +0,0 @@
package top.niunaijun.blackdex
import android.app.Application
import android.content.Context
import top.niunaijun.blackbox.BlackDexCore
import top.niunaijun.blackbox.app.configuration.ClientConfiguration
import top.niunaijun.blackdex.data.BlackDexConfiguration
/**
*
* @Description:
* @Author: wukaicheng
* @CreateDate: 2021/5/23 14:00
*/
class App : Application() {
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
BlackDexCore.get().doAttachBaseContext(base,BlackDexConfiguration(base!!))
}
override fun onCreate() {
super.onCreate()
BlackDexCore.get().doCreate()
}
}

@ -0,0 +1,40 @@
package top.niunaijun.blackboxa.app
import android.annotation.SuppressLint
import android.app.Application
import android.content.Context
import com.umeng.commonsdk.UMConfigure
import top.niunaijun.blackdex.app.AppManager
/**
*
* @Description:
* @Author: wukaicheng
* @CreateDate: 2021/4/29 21:21
*/
class App : Application() {
companion object {
@SuppressLint("StaticFieldLeak")
@Volatile
private lateinit var mContext: Context
@JvmStatic
fun getContext(): Context {
return mContext
}
}
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
mContext = base!!
UMConfigure.init(base, "60b373136c421a3d97d23c29", "Github", 0, "")
AppManager.doAttachBaseContext(base)
}
override fun onCreate() {
super.onCreate()
AppManager.doOnCreate(mContext)
}
}

@ -0,0 +1,26 @@
package top.niunaijun.blackdex.app
import android.content.Context
object AppManager {
@JvmStatic
val mBlackBoxLoader by lazy {
BlackDexLoader()
}
fun doAttachBaseContext(context: Context) {
try {
mBlackBoxLoader.attachBaseContext(context)
mBlackBoxLoader.addLifecycleCallback()
} catch (e: Exception) {
e.printStackTrace()
}
}
fun doOnCreate(context: Context) {
mBlackBoxLoader.doOnCreate(context)
initThirdService(context)
}
private fun initThirdService(context: Context) {}
}

@ -0,0 +1,87 @@
package top.niunaijun.blackdex.app
import android.content.Context
import top.niunaijun.blackbox.BlackDexCore
import top.niunaijun.blackbox.app.configuration.ClientConfiguration
import top.niunaijun.blackbox.utils.FileUtils
import top.niunaijun.blackbox.utils.compat.BuildCompat
import top.niunaijun.blackboxa.app.App
import top.niunaijun.blackdex.biz.cache.AppSharedPreferenceDelegate
import java.io.File
/**
*
* @Description:
* @Author: wukaicheng
* @CreateDate: 2021/5/6 23:38
*/
class BlackDexLoader {
private var mSavePath by AppSharedPreferenceDelegate(App.getContext(), "")
private var mSaveEnable by AppSharedPreferenceDelegate(App.getContext(), true)
private var mDir = if (mSaveEnable) {
getDexDumpDir(App.getContext())
} else {
mSavePath
}
fun addLifecycleCallback() {
}
fun attachBaseContext(context: Context) {
BlackDexCore.get().doAttachBaseContext(context, object : ClientConfiguration() {
override fun getHostPackageName(): String {
return context.packageName
}
override fun getDexDumpDir(): String {
return mDir
}
})
}
fun doOnCreate(context: Context) {
BlackDexCore.get().doCreate()
}
fun saveEnable(): Boolean {
return mSaveEnable
}
fun saveEnable(state: Boolean) {
this.mSaveEnable = state
}
fun getSavePath(): String {
return mSavePath
}
fun setSavePath(path: String) {
this.mSavePath = path
}
companion object {
val TAG: String = BlackDexLoader::class.java.simpleName
fun getDexDumpDir(context: Context): String {
return if (BuildCompat.isR()) {
val dump = File(
context.externalCacheDir?.parentFile?.parentFile?.parentFile?.parentFile,
"Download/dexDump"
)
FileUtils.mkdirs(dump)
dump.absolutePath
} else {
val dump = File(context.externalCacheDir?.parentFile, "dump")
FileUtils.mkdirs(dump)
dump.absolutePath
}
}
}
}

@ -0,0 +1,67 @@
package top.niunaijun.blackdex.biz.cache
import android.content.Context
import android.text.TextUtils
import androidx.core.content.edit
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
/**
*
* @desc:目前只支持 5种基本数据类型如果要支持obj请继承该类并重写他的相关方法 findData/putData
*
* @author: mini
* @created by 2021/5/10
*/
open class AppSharedPreferenceDelegate<Data>(context: Context, private val default: Data, spName: String? = null) : ReadWriteProperty<Any, Data?> {
private val mSharedPreferences by lazy {
val tmpCacheName = if (TextUtils.isEmpty(spName)) {
AppSharedPreferenceDelegate::class.java.simpleName
} else {
spName
}
return@lazy context.getSharedPreferences(tmpCacheName, Context.MODE_PRIVATE)
}
override fun getValue(thisRef: Any, property: KProperty<*>): Data {
return findData(property.name, default)
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: Data?) {
putData(property.name, value)
}
protected fun findData(key: String, default: Data): Data {
with(mSharedPreferences) {
val result: Any? = when (default) {
is Int -> getInt(key, default)
is Long -> getLong(key, default)
is Float -> getFloat(key, default)
is String -> getString(key, default)
is Boolean -> getBoolean(key, default)
else -> throw IllegalArgumentException("This type $default can not be saved into sharedPreferences")
}
return result as? Data ?: default
}
}
protected fun putData(key: String, value: Data?) {
mSharedPreferences.edit {
if (value == null) {
remove(key)
} else {
when (value) {
is Int -> putInt(key, value)
is Long -> putLong(key, value)
is Float -> putFloat(key, value)
is String -> putString(key, value)
is Boolean -> putBoolean(key, value)
else -> throw IllegalArgumentException("This type $default can not be saved into Preferences")
}
}
}
}
}

@ -1,41 +0,0 @@
package top.niunaijun.blackdex.data
import android.content.Context
import top.niunaijun.blackbox.app.configuration.ClientConfiguration
import top.niunaijun.blackbox.utils.FileUtils
import top.niunaijun.blackbox.utils.compat.BuildCompat
import java.io.File
/**
*
* @Description: 启动配置文件
* @Author: wukaicheng
* @CreateDate: 2021/5/23 14:04
*/
class BlackDexConfiguration(private val context: Context) : ClientConfiguration() {
companion object {
fun getDexDumpDir(context: Context): String {
return if (BuildCompat.isR()) {
val dump = File(context.externalCacheDir?.parentFile?.parentFile?.parentFile?.parentFile, "Download/dexDump")
FileUtils.mkdirs(dump)
dump.absolutePath
} else {
val dump = File(context.externalCacheDir?.parentFile, "dump")
FileUtils.mkdirs(dump)
dump.absolutePath
}
}
}
private val dir = getDexDumpDir(context)
override fun getHostPackageName(): String {
return context.packageName
}
override fun getDexDumpDir(): String {
return dir
}
}

@ -28,7 +28,8 @@ class DexDumpRepository {
fun getAppList(mAppListLiveData: MutableLiveData<List<AppInfo>>) {
val installedApplications: List<ApplicationInfo> = getPackageManager().getInstalledApplications(0)
val installedApplications: List<ApplicationInfo> =
getPackageManager().getInstalledApplications(0)
val installedList = mutableListOf<AppInfo>()
for (installedApplication in installedApplications) {
@ -56,30 +57,32 @@ class DexDumpRepository {
val result = if (URLUtil.isValidUrl(source)) {
BlackDexCore.get().dumpDex(Uri.parse(source))
} else if (source.contains("/")) {
BlackDexCore.get().dumpDex(File(source))
} else {
BlackDexCore.get().dumpDex(source)
}
if(result){
if (result) {
dumpTaskId++
startCountdown(dexDumpLiveData)
}else{
} else {
dexDumpLiveData.postValue(DumpInfo(DumpInfo.TIMEOUT))
}
}
fun dumpSuccess(){
fun dumpSuccess() {
dumpTaskId++
}
private fun startCountdown(dexDumpLiveData: MutableLiveData<DumpInfo>){
private fun startCountdown(dexDumpLiveData: MutableLiveData<DumpInfo>) {
GlobalScope.launch {
val tempId = dumpTaskId
delay(10000)
if(tempId == dumpTaskId){
if (tempId == dumpTaskId) {
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() {
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)
toolbar.setTitle(title)
if (showBack) {
@ -20,10 +25,13 @@ open class BaseActivity : AppCompatActivity() {
toolbar.setNavigationOnClickListener {
if (onBack != null) {
onBack()
}
} else {
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,36 +1,35 @@
package top.niunaijun.blackdex.view.main
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.os.Environment
import android.view.Menu
import android.view.MenuItem
import android.view.inputmethod.InputMethodManager
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.files.fileChooser
import com.ferfalk.simplesearchview.SimpleSearchView
import com.roger.catloadinglibrary.CatLoadingView
import com.umeng.analytics.MobclickAgent
import top.niunaijun.blackbox.BlackDexCore
import top.niunaijun.blackbox.core.system.dump.IBDumpMonitor
import top.niunaijun.blackbox.entity.dump.DumpResult
import top.niunaijun.blackbox.utils.compat.BuildCompat
import top.niunaijun.blackdex.R
import top.niunaijun.blackdex.data.entity.AppInfo
import top.niunaijun.blackdex.data.entity.DumpInfo
import top.niunaijun.blackdex.databinding.ActivityMainBinding
import top.niunaijun.blackdex.util.FileUtil
import top.niunaijun.blackdex.util.InjectionUtil
import top.niunaijun.blackdex.util.LoadingUtil
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
class MainActivity : BaseActivity() {
class MainActivity : PermissionActivity() {
private val viewBinding: ActivityMainBinding by inflate()
@ -47,11 +46,8 @@ class MainActivity : BaseActivity() {
setContentView(viewBinding.root)
initToolbar(viewBinding.toolbarLayout.toolbar, R.string.app_name)
initView()
initViewModel()
initSearchView()
BlackDexCore.get().registerDumpMonitor(mMonitor)
@ -73,7 +69,25 @@ class MainActivity : BaseActivity() {
}
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()
}
}
@ -105,8 +119,9 @@ class MainActivity : BaseActivity() {
DumpInfo.TIMEOUT -> {
loadingView.dismiss()
MaterialDialog(this).show {
title(text = "脱壳失败")
message(text = "未知错误,可能是不兼容或者带有环境检测导致失败,可前往GitHub(https://github.com/CodingGay/BlackDex)提Issue")
title(res = R.string.unpack_fail)
message(res = R.string.jump_issue)
negativeButton(res = R.string.github) {
negativeButton(text = "Github") {
val intent = Intent(
Intent.ACTION_VIEW,
@ -114,22 +129,23 @@ class MainActivity : BaseActivity() {
)
startActivity(intent)
}
positiveButton(text = "确定")
positiveButton(res = R.string.confirm)
}
}
}
else -> {
viewModel.dexDumpSuccess()
val title = if (it.state == DumpInfo.SUCCESS) {
"脱壳成功"
getString(R.string.unpack_success)
} else {
"脱壳失败"
getString(R.string.unpack_fail)
}
loadingView.dismiss()
MaterialDialog(this).show {
title(text = title)
message(text = it.msg)
positiveButton(text = "确定")
positiveButton(res = R.string.confirm)
}
}
}
@ -145,14 +161,14 @@ class MainActivity : BaseActivity() {
viewModel.mDexDumpLiveData.postValue(
DumpInfo(
DumpInfo.SUCCESS,
"DEX文件储存在:${result.dir}"
getString(R.string.dex_save, result.dir)
)
)
} else {
viewModel.mDexDumpLiveData.postValue(
DumpInfo(
DumpInfo.FAIL,
"错误原因: ${result.msg}"
getString(R.string.error_msg, result.msg)
)
)
}
@ -181,7 +197,6 @@ class MainActivity : BaseActivity() {
})
}
private fun filterApp(newText: String) {
val newList = this.appList.filter {
it.name.contains(newText, true) or it.packageName.contains(newText, true)
@ -204,59 +219,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
try {
startActivity(intent)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
negativeButton(text = "退出软件") {
finish()
}
}
}
}
override fun onStart() {
super.onStart()
requestStoragePermission()
}
override fun onBackPressed() {
if (viewBinding.searchView.isSearchOpen) {
viewBinding.searchView.closeSearch()
@ -283,9 +245,24 @@ class MainActivity : BaseActivity() {
Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/CodingGay/BlackDex"))
startActivity(intent)
}
R.id.main_setting -> {
val intent =
Intent(this, SettingActivity::class.java)
startActivity(intent)
}
}
return super.onOptionsItemSelected(item)
}
override fun onResume() {
super.onResume()
MobclickAgent.onResume(this)
}
override fun onPause() {
super.onPause()
MobclickAgent.onPause(this)
}
}

@ -0,0 +1,25 @@
package top.niunaijun.blackdex.view.setting
import android.os.Bundle
import top.niunaijun.blackdex.R
import top.niunaijun.blackdex.databinding.ActivitySettingBinding
import top.niunaijun.blackdex.util.inflate
import top.niunaijun.blackdex.view.base.BaseActivity
import top.niunaijun.blackdex.view.base.PermissionActivity
class SettingActivity : PermissionActivity() {
private val viewBinding: ActivitySettingBinding by inflate()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(viewBinding.root)
initToolbar(viewBinding.toolbarLayout.toolbar, R.string.app_setting,true)
supportFragmentManager.beginTransaction().replace(R.id.fragment,SettingFragment()).commit()
}
fun setRequestCallback(callback:((Boolean)->Unit)?){
this.requestPermissionCallback = callback
requestStoragePermission()
}
}

@ -0,0 +1,87 @@
package top.niunaijun.blackdex.view.setting
import android.os.Bundle
import android.os.Environment
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreferenceCompat
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.files.folderChooser
import top.niunaijun.blackboxa.app.App
import top.niunaijun.blackdex.R
import top.niunaijun.blackdex.app.AppManager
import top.niunaijun.blackdex.app.BlackDexLoader
import java.io.File
/**
*
* @Description:
* @Author: wukaicheng
* @CreateDate: 2021/5/28 19:55
*/
class SettingFragment : PreferenceFragmentCompat() {
private lateinit var savePathPreference: Preference
private lateinit var saveEnablePreference: SwitchPreferenceCompat
private val initialDirectory = AppManager.mBlackBoxLoader.getSavePath()
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.setting)
savePathPreference = findPreference("save_path")!!
savePathPreference.onPreferenceClickListener = mSavedPathClick
savePathPreference.summary = initialDirectory
saveEnablePreference = findPreference("save_enable")!!
saveEnablePreference.onPreferenceChangeListener = mSaveEnableChange
saveEnablePreference.isChecked = AppManager.mBlackBoxLoader.saveEnable()
}
private val mSavedPathClick = Preference.OnPreferenceClickListener {
val initialFile = with(initialDirectory) {
if (initialDirectory.isEmpty()) {
Environment.getExternalStorageDirectory()
} else {
File(this)
}
}
MaterialDialog(requireContext()).show {
folderChooser(
requireContext(),
initialDirectory = initialFile,
allowFolderCreation = true
) { _, file ->
AppManager.mBlackBoxLoader.setSavePath(file.absolutePath)
savePathPreference.summary = file.absolutePath
}
negativeButton(res = R.string.cancel)
}
return@OnPreferenceClickListener true
}
private val mSaveEnableChange = Preference.OnPreferenceChangeListener { _, newValue ->
if (newValue == false) {
(requireActivity() as SettingActivity).setRequestCallback(requestResult)
} else {
AppManager.mBlackBoxLoader.saveEnable(true)
saveEnablePreference.isChecked = 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,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".view.setting.SettingActivity">
<include
android:id="@+id/toolbar_layout"
layout="@layout/view_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

@ -9,6 +9,11 @@
android:title="@string/filter"
app:showAsAction="ifRoom" />
<item
android:id="@+id/main_setting"
android:title="@string/app_setting"
app:showAsAction="never"/>
<item
android:id="@+id/main_git"
android:title="@string/open_source"

@ -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,6 +1,26 @@
<resources>
<string name="filter">过滤</string>
<string name="choose">选择</string>
<string name="log">软件日志</string>
<string name="open_source">开源地址</string>
<string name="filter">Filter</string>
<string name="choose">Select</string>
<string name="log">Logcat</string>
<string name="open_source">Open Source</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,This may be an incompatibility or may have an environmental detection that causes the failure,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>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="@string/file_save">
<SwitchPreferenceCompat
android:disableDependentsState="true"
android:key="save_enable"
android:title="@string/use_default_file" />
<Preference
android:dependency="save_enable"
android:key="save_path"
android:title="@string/rewrite_file_path" />
</PreferenceCategory>
</PreferenceScreen>

@ -10,7 +10,7 @@ buildscript {
jcenter { url 'https://maven.aliyun.com/repository/jcenter' }
jcenter { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
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' }
}
dependencies {
@ -30,7 +30,7 @@ allprojects {
jcenter { url 'https://maven.aliyun.com/repository/jcenter' }
jcenter { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
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' }
}
}

Loading…
Cancel
Save