仅在首次启动时授予存储权限后,应用程序崩溃

时间:2018-08-27 05:47:38

标签: android kotlin android-permissions

当我的app第一次启动时,我进入一个标签,要求输入storage permission,它崩溃了。在那之后,它工作正常。基本上,在授予external storage之后,它应该在assets folder上创建一个文件夹,其中包含我项目中storage permission中的文件。首次崩溃并重新打开后,它不会崩溃,并且可以正确放置目录和文件。 如果该文件夹已经在external storage上,则在第一次启动时不会崩溃。另外,我后来意识到,可以通过定位SDK version 21来完全摆脱崩溃,但是如果这样做,我将无法更新Play Store上的应用程序,因为我已经提交了该应用程序,希望以后可以解决此崩溃问题。这是崩溃期间的日志猫:

    --------- beginning of crash
08-27 01:16:58.548 17674-17674/com.thirdeclarity.rcmloader E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.thirdeclarity.rcmloader, PID: 17674
java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=65661, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {com.thirdeclarity.rcmloader/com.pavelrekun.rekado.screens.main_activity.MainActivity}: java.io.FileNotFoundException: /storage/emulated/0/RCM Loader/hekate-4.0.bin (No such file or directory)
    at android.app.ActivityThread.deliverResults(ActivityThread.java:4269)
    at android.app.ActivityThread.handleSendResult(ActivityThread.java:4313)
    at android.app.ActivityThread.-wrap19(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1645)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6499)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:440)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
 Caused by: java.io.FileNotFoundException: /storage/emulated/0/RCM Loader/hekate-4.0.bin (No such file or directory)
    at java.io.FileOutputStream.open0(Native Method)
    at java.io.FileOutputStream.open(FileOutputStream.java:287)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:223)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:110)
    at com.pavelrekun.rekado.services.utils.MemoryUtils.copyAsset(MemoryUtils.kt:15)
    at com.pavelrekun.rekado.screens.payload_fragment.PayloadsView.initList(PayloadsView.kt:47)
    at com.pavelrekun.rekado.screens.payload_fragment.PayloadsView.onRequestPermissionsResult(PayloadsView.kt:81)
    at com.pavelrekun.rekado.screens.payload_fragment.PayloadsFragment.onRequestPermissionsResult(PayloadsFragment.kt:33)
    at android.support.v4.app.FragmentActivity.onRequestPermissionsResult(FragmentActivity.java:804)
    at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:7429)
    at android.app.Activity.dispatchActivityResult(Activity.java:7280)
    at android.app.ActivityThread.deliverResults(ActivityThread.java:4265)
    at android.app.ActivityThread.handleSendResult(ActivityThread.java:4313) 
    at android.app.ActivityThread.-wrap19(Unknown Source:0) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1645) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:164) 
    at android.app.ActivityThread.main(ActivityThread.java:6499) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:440) 
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) 
  08-27 01:16:58.689 17674-17689/com.thirdeclarity.rcmloader I/zygote: Background concurrent copying GC freed 22378(1560KB) AllocSpace objects, 2(104KB) LOS objects, 50% free, 2MB/4MB, paused 2.770ms total 145.331ms

我是Android开发的新手,正在使用的代码来自一个开源项目,但我相信这是与崩溃的选项卡相关的代码:

package com.pavelrekun.rekado.screens.payload_fragment

import android.Manifest
import android.content.pm.PackageManager
import android.support.v4.app.Fragment
import android.support.v7.widget.LinearLayoutManager
import android.widget.Toast
import com.pavelrekun.konae.Konae
import com.pavelrekun.konae.filters.ExtensionFileFilter
import com.pavelrekun.rang.utils.ColorsHelper
import com.pavelrekun.rekado.R
import com.pavelrekun.rekado.base.BaseActivity
import com.pavelrekun.rekado.data.Payload
import com.pavelrekun.rekado.screens.payload_fragment.adapters.PayloadsAdapter
import com.pavelrekun.rekado.services.eventbus.Events
import com.pavelrekun.rekado.services.logs.LogHelper
import com.pavelrekun.rekado.services.payloads.PayloadHelper
import com.pavelrekun.rekado.services.utils.MemoryUtils
import com.pavelrekun.rekado.services.utils.PermissionsUtils
import kotlinx.android.synthetic.main.fragment_payloads.*
import org.greenrobot.eventbus.EventBus
import java.io.File
import java.io.IOException


class PayloadsView(private val activity: BaseActivity, private val fragment: Fragment) : PayloadsContract.View {

    private lateinit var adapter: PayloadsAdapter

    override fun initViews() {
        activity.setTitle(R.string.navigation_payloads)

        prepareList()
        initClickListeners()
        initDesign()
    }

    override fun prepareList() {
        if (!PermissionsUtils.checkPermissionGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            PermissionsUtils.showPermissionDialog(activity, fragment, PermissionsUtils.PERMISSIONS_READ_REQUEST_CODE)
        } else {
            initList()
        }
    }

    override fun initList() {
        MemoryUtils.copyAsset()

        adapter = PayloadsAdapter(PayloadHelper.getAll())

        activity.payloadsList.setHasFixedSize(true)
        activity.payloadsList.layoutManager = LinearLayoutManager(activity)
        activity.payloadsList.adapter = adapter
    }

    override fun initDesign() {
        activity.payloadsAdd.setColorFilter(ColorsHelper.getContrastColor(activity, ColorsHelper.resolveAccentColor(activity)))
    }

    override fun updateList() {
        if (this::adapter.isInitialized) {
            adapter.updateList()
        }
    }

    override fun initClickListeners() {
        activity.payloadsAdd.setOnClickListener { addPayload() }
    }

    override fun addPayload() {
        if (!PermissionsUtils.checkPermissionGranted(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            PermissionsUtils.showPermissionDialog(activity, fragment, PermissionsUtils.PERMISSIONS_WRITE_REQUEST_CODE)
        } else {
            getPayloadFromStorage()
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        when (requestCode) {
            PermissionsUtils.PERMISSIONS_READ_REQUEST_CODE -> if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                initList()
            }
            PermissionsUtils.PERMISSIONS_WRITE_REQUEST_CODE -> if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                getPayloadFromStorage()
            } else {
                Toast.makeText(activity, R.string.permission_storage_error, Toast.LENGTH_SHORT).show()
            }
        }
    }

    private fun getPayloadFromStorage() {
        Konae().with(activity)
                .withChosenListener(object : Konae.Result {
                    override fun onChoosePath(dirFile: File) {
                        onChosenFileListener(dirFile)
                    }
                })
                .withFileFilter(ExtensionFileFilter("bin"))
                .withTitle(activity.getString(R.string.dialog_file_chooser_payload_title))
                .build()
                .show()
    }

    private fun onChosenFileListener(pathFile: File) {
        val payload = Payload(PayloadHelper.getName(pathFile.absolutePath), PayloadHelper.getPath(PayloadHelper.getName(pathFile.absolutePath)))

        if (!payload.name.contains("bin")) {
            Toast.makeText(activity, activity.getString(R.string.helper_error_file_payload_wrong), Toast.LENGTH_SHORT).show()
        }

        try {
            MemoryUtils.toFile(pathFile, (PayloadHelper.FOLDER_PATH + "/" + payload.name))

            EventBus.getDefault().post(Events.UpdatePayloadsListEvent())
            LogHelper.log(LogHelper.INFO, "Added new payload: ${payload.name}")
        } catch (e: IOException) {
            e.printStackTrace()
            LogHelper.log(LogHelper.ERROR, "Failed to add payload: ${payload.name}")
        }
    }
}

以下是最可能相关的代码:

package com.pavelrekun.rekado.services.payloads

import android.os.Environment
import com.pavelrekun.rekado.data.Payload
import io.paperdb.Paper
import java.io.File


object PayloadHelper {

    val FOLDER_PATH = "${Environment.getExternalStorageDirectory()}/RCM Loader/"
    const val BASIC_PAYLOAD_NAME = "hekate-4.0.bin"

    private const val CHOSEN_PAYLOAD = "CHOSEN_PAYLOAD"

    fun init() {
        val folderFile = File(FOLDER_PATH)
        if (!folderFile.exists()) folderFile.mkdirs()
    }

    fun getAll(): MutableList<Payload> {
        val payloads: MutableList<Payload> = ArrayList()

        File(FOLDER_PATH).listFiles().forEach {
            if (it.path.contains("bin")) {
                payloads.add(Payload(getName(it.path), it.path))
            }
        }

        return payloads
    }

    fun clearFolder() {
        File(FOLDER_PATH).listFiles().forEach {
            if (it.name != BASIC_PAYLOAD_NAME) {
                it.delete()
            }
        }
    }

    fun getNames(): MutableList<String> {
        val payloads: MutableList<String> = ArrayList()

        for (payload in getAll()) {
            payloads.add(payload.name)
        }

        return payloads
    }

    fun getName(path: String): String {
        return File(path).name
    }

    fun getPath(name: String): String {
        return "$FOLDER_PATH/$name"
    }

    fun find(name: String): Payload? {
        for (payload in getAll()) {
            if (payload.name == name) {
                return payload
            }
        }

        return null
    }

    fun putChosen(payload: Payload) {
        Paper.book().write(CHOSEN_PAYLOAD, payload)
    }

    fun getChosen(): Payload {
        return Paper.book().read(CHOSEN_PAYLOAD)
    }
}

-     包com.pavelrekun.rekado.services.utils

import android.Manifest
import android.app.Activity
import android.content.pm.PackageManager
import android.support.v4.app.Fragment
import android.support.v4.content.ContextCompat
import android.support.v7.app.AlertDialog

import com.pavelrekun.rekado.R

object PermissionsUtils {

    const val PERMISSIONS_READ_REQUEST_CODE = 125
    const val PERMISSIONS_WRITE_REQUEST_CODE = 126

    private fun requestPermissions(fragment: Fragment, permissions: Array<String>, code: Int) {
        fragment.requestPermissions(permissions, code)
    }

    fun checkPermissionGranted(activity: Activity, permission: String): Boolean {
        val result = ContextCompat.checkSelfPermission(activity, permission)
        return result == PackageManager.PERMISSION_GRANTED
    }

    fun showPermissionDialog(activity: Activity, fragment: Fragment, code: Int) {
        val builder = AlertDialog.Builder(activity)
        builder.setTitle(R.string.permission_storage_dialog_title)
        builder.setMessage(R.string.permission_storage_dialog_description)

        val storagePermissionDialog = builder.create()
        storagePermissionDialog.setButton(AlertDialog.BUTTON_POSITIVE, activity.getString(R.string.permission_storage_button)) { _, _ ->
            storagePermissionDialog.dismiss()
            requestPermissions(fragment, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), code)
        }

        storagePermissionDialog.show()
    }
}

MemoryUtils:

package com.pavelrekun.rekado.services.utils

import com.pavelrekun.rekado.RekadoApplication
import com.pavelrekun.rekado.services.eventbus.Events
import com.pavelrekun.rekado.services.payloads.PayloadHelper
import org.greenrobot.eventbus.EventBus
import java.io.*

object MemoryUtils {

    fun copyAsset() {
        val assetManager = RekadoApplication.instance.applicationContext.assets
        val sxPayloadFile = assetManager.open(PayloadHelper.BASIC_PAYLOAD_NAME)

        copyFile(sxPayloadFile, FileOutputStream("${PayloadHelper.FOLDER_PATH}/${PayloadHelper.BASIC_PAYLOAD_NAME}"))

        EventBus.getDefault().post(Events.UpdatePayloadsListEvent())
    }

    @Throws(IOException::class)
    private fun copyFile(inputStream: InputStream, outputStream: OutputStream) {
        inputStream.use { input ->
            outputStream.use { output ->
                input.copyTo(output)
            }
        }
    }

    fun removeFile(path: String) {
        File(path).delete()
    }

    fun toFile(file: File, path: String): File {
        return file.copyTo(File(path), true)
    }
}

RekadoApplication

package com.pavelrekun.rekado

import android.annotation.SuppressLint
import android.app.Application
import android.support.v7.app.AppCompatDelegate
import com.pavelrekun.rang.Rang
import com.pavelrekun.rekado.services.logs.LogHelper
import com.pavelrekun.rekado.services.payloads.PayloadHelper
import io.paperdb.Paper

@SuppressLint("StaticFieldLeak")
class RekadoApplication : Application() {

    companion object {
        lateinit var instance: RekadoApplication
    }

    override fun onCreate() {
        super.onCreate()

        instance = this

        Paper.init(this)

        LogHelper.init()
        PayloadHelper.init()

        Rang.defaults().primaryColor().accentColor().nightMode().oledMode()
        Rang.init(this)
    }

}

如果有人检查了代码并试图弄清为什么在请求和授予存储权限以及“ RCM”之后立即单击应用程序中的“有效负载”选项卡时崩溃(仅在首次安装后一次)会崩溃,我将非常感谢在存储设备上找不到“加载程序”文件夹。崩溃后,该应用程序运行正常,并使用文件夹内的捆绑bin文件创建了该文件夹,但我想首先找出导致崩溃的原因:https://github.com/ThirdEyeClarity/RCM-Loader?files=1

1 个答案:

答案 0 :(得分:1)

通过以下一行查看logcat:

Caused by: java.io.FileNotFoundException: /storage/emulated/0/RCM Loader/hekate-4.0.bin (No such file or directory)

在您展示给我们的代码中,我想知道有关PayloadHelper.init()方法的问题:

fun init() {
    val folderFile = File(FOLDER_PATH)
    if (!folderFile.exists()) folderFile.mkdirs()
}

在这些示例中的任何地方都看不到对其的任何调用。 您能告诉我们使用init()方法的地方吗?