|
|
|
@ -1,38 +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() |
|
|
|
|
|
|
|
|
@ -72,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() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -104,31 +119,31 @@ class MainActivity : BaseActivity() { |
|
|
|
|
DumpInfo.TIMEOUT -> { |
|
|
|
|
loadingView.dismiss() |
|
|
|
|
MaterialDialog(this).show { |
|
|
|
|
title(text = "脱壳失败") |
|
|
|
|
message(text = "未知错误,可前往GitHub(https://github.com/CodingGay/BlackDex)提Issue") |
|
|
|
|
negativeButton(text = "Github") { |
|
|
|
|
title(res = R.string.unpack_fail) |
|
|
|
|
message(res = R.string.jump_issue) |
|
|
|
|
negativeButton(res = R.string.github) { |
|
|
|
|
val intent = Intent( |
|
|
|
|
Intent.ACTION_VIEW, |
|
|
|
|
Uri.parse("https://github.com/CodingGay/BlackDex/issues") |
|
|
|
|
) |
|
|
|
|
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) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -144,14 +159,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) |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
@ -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() { |
|
|
|
|
if (viewBinding.searchView.isSearchOpen) { |
|
|
|
|
viewBinding.searchView.closeSearch() |
|
|
|
@ -285,4 +254,13 @@ class MainActivity : BaseActivity() { |
|
|
|
|
return super.onOptionsItemSelected(item) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
override fun onResume() { |
|
|
|
|
super.onResume() |
|
|
|
|
MobclickAgent.onResume(this) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
override fun onPause() { |
|
|
|
|
super.onPause() |
|
|
|
|
MobclickAgent.onPause(this) |
|
|
|
|
} |
|
|
|
|
} |