commit
9e49e89e78
@ -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 |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -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 |
||||||
|
} |
||||||
|
} |
@ -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() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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> |
@ -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> |
<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">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> |
</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> |
Loading…
Reference in new issue