1.可自定义dex文件保存位置

pull/10/head
kai-city 3 years ago
parent 0fdd3b6fbd
commit 87217696dd
  1. 6
      app/build.gradle
  2. 25
      app/src/main/AndroidManifest.xml
  3. 26
      app/src/main/java/top/niunaijun/blackdex/App.kt
  4. 38
      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. 3
      app/src/main/java/top/niunaijun/blackdex/view/base/BaseActivity.kt
  10. 21
      app/src/main/java/top/niunaijun/blackdex/view/main/MainActivity.kt
  11. 19
      app/src/main/java/top/niunaijun/blackdex/view/setting/SettingActivity.kt
  12. 61
      app/src/main/java/top/niunaijun/blackdex/view/setting/SettingFragment.kt
  13. 22
      app/src/main/res/layout/activity_setting.xml
  14. 5
      app/src/main/res/menu/menu_main.xml
  15. 1
      app/src/main/res/values/strings.xml
  16. 15
      app/src/main/res/xml/setting.xml

@ -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'
//

@ -3,29 +3,38 @@
xmlns:tools="http://schemas.android.com/tools"
package="top.niunaijun.blackdex">
<!-- Android 11 需要 -->
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
<!-- Android 11 需要 -->
<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,38 @@
package top.niunaijun.blackboxa.app
import android.annotation.SuppressLint
import android.app.Application
import android.content.Context
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!!
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(), false)
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,
"hupu/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
}
}

@ -20,8 +20,9 @@ open class BaseActivity : AppCompatActivity() {
toolbar.setNavigationOnClickListener {
if (onBack != null) {
onBack()
}else{
finish()
}
finish()
}
}
}

@ -29,6 +29,8 @@ 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.setting.SettingActivity
class MainActivity : BaseActivity() {
@ -47,11 +49,8 @@ class MainActivity : BaseActivity() {
setContentView(viewBinding.root)
initToolbar(viewBinding.toolbarLayout.toolbar, R.string.app_name)
initView()
initViewModel()
initSearchView()
BlackDexCore.get().registerDumpMonitor(mMonitor)
@ -181,7 +180,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)
@ -224,24 +222,17 @@ class MainActivity : BaseActivity() {
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()
}
startActivity(intent)
}
}
negativeButton(text = "退出软件") {
@ -283,6 +274,12 @@ 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)

@ -0,0 +1,19 @@
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
class SettingActivity : BaseActivity() {
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()
}
}

@ -0,0 +1,61 @@
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.blackdex.R
import top.niunaijun.blackdex.app.AppManager
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
}
private val mSavedPathClick = Preference.OnPreferenceClickListener {
val initialFile = with(initialDirectory) {
if (initialDirectory.isEmpty()) {
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
} else {
File(this)
}
}
MaterialDialog(requireContext()).show {
folderChooser(requireContext(), initialDirectory = initialFile,allowFolderCreation = true) { _, file ->
AppManager.mBlackBoxLoader.setSavePath(file.absolutePath)
savePathPreference.summary = file.absolutePath
}
}
return@OnPreferenceClickListener true
}
private val mSaveEnableChange = Preference.OnPreferenceChangeListener { _, newValue ->
AppManager.mBlackBoxLoader.saveEnable(newValue as Boolean)
return@OnPreferenceChangeListener true
}
}

@ -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"

@ -3,4 +3,5 @@
<string name="choose">选择</string>
<string name="log">软件日志</string>
<string name="open_source">开源地址</string>
<string name="app_setting">软件设置</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="文件储存">
<SwitchPreferenceCompat
android:disableDependentsState="true"
android:key="save_enable"
android:title="使用默认储存路径" />
<Preference
android:dependency="save_enable"
android:key="save_path"
android:title="自定义储存路径" />
</PreferenceCategory>
</PreferenceScreen>
Loading…
Cancel
Save