feat: Update storage permission handling for image access
- Implemented request for READ_EXTERNAL_STORAGE permission to allow users to select images. - Optimized permission request logic to avoid unnecessary prompts if permission has already been granted. - Added user-friendly dialogs to guide users to app settings when permissions are denied. - Enhanced error handling and logging for WebView to improve debugging and user experience. - Loaded last entered URL from SharedPreferences for better usability. - Updated UI interactions to hide input elements when loading web content. - Remove unnecessary permission granted. This update improves the overall user experience by streamlining the permission process and enhancing image selection functionality.
This commit is contained in:
parent
1e2bcee52c
commit
c4f50c2c14
3 changed files with 34 additions and 93 deletions
|
|
@ -4,6 +4,14 @@
|
||||||
<selectionStates>
|
<selectionStates>
|
||||||
<SelectionState runConfigName="Unnamed">
|
<SelectionState runConfigName="Unnamed">
|
||||||
<option name="selectionMode" value="DROPDOWN" />
|
<option name="selectionMode" value="DROPDOWN" />
|
||||||
|
<DropdownSelection timestamp="2024-10-05T10:05:39.736702200Z">
|
||||||
|
<Target type="DEFAULT_BOOT">
|
||||||
|
<handle>
|
||||||
|
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\Archol\.android\avd\Pixel_5_API_28.avd" />
|
||||||
|
</handle>
|
||||||
|
</Target>
|
||||||
|
</DropdownSelection>
|
||||||
|
<DialogSelection />
|
||||||
</SelectionState>
|
</SelectionState>
|
||||||
</selectionStates>
|
</selectionStates>
|
||||||
</component>
|
</component>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
<!-- 允许应用访问互联网 -->
|
<!-- 允许应用访问互联网 -->
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
|
|
||||||
|
|
||||||
<!-- 添加 namespace -->
|
<!-- 添加 namespace -->
|
||||||
<application
|
<application
|
||||||
|
|
|
||||||
|
|
@ -1,48 +1,48 @@
|
||||||
package com.example.lobchat
|
package com.example.lobchat
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.webkit.*
|
import android.webkit.*
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import androidx.core.app.ActivityCompat
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.provider.Settings
|
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private lateinit var webView: WebView
|
private lateinit var webView: WebView
|
||||||
private lateinit var urlInputLayout: ConstraintLayout
|
|
||||||
private lateinit var urlInput: EditText
|
|
||||||
private lateinit var loadUrlButton: Button
|
|
||||||
private var filePathCallback: ValueCallback<Array<Uri>>? = null
|
private var filePathCallback: ValueCallback<Array<Uri>>? = null
|
||||||
private lateinit var fileChooserLauncher: ActivityResultLauncher<Intent>
|
private lateinit var fileChooserLauncher: ActivityResultLauncher<Intent>
|
||||||
|
|
||||||
|
private lateinit var urlInput: EditText
|
||||||
|
private lateinit var loadUrlButton: Button
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val SHARED_PREFS_NAME = "lobchat_prefs"
|
||||||
|
const val KEY_SAVED_URL = "saved_url"
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
// 初始化视图组件
|
// 初始化视图组件
|
||||||
webView = findViewById(R.id.webView)
|
webView = findViewById(R.id.webView)
|
||||||
urlInputLayout = findViewById(R.id.urlInputLayout)
|
|
||||||
urlInput = findViewById(R.id.urlInput)
|
urlInput = findViewById(R.id.urlInput)
|
||||||
loadUrlButton = findViewById(R.id.loadUrlButton)
|
loadUrlButton = findViewById(R.id.loadUrlButton)
|
||||||
|
|
||||||
// 检查并请求存储权限
|
// 从 SharedPreferences 加载上次保存的 URL
|
||||||
if (!hasStoragePermission()) {
|
val sharedPreferences = getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE)
|
||||||
requestStoragePermission()
|
val savedUrl = sharedPreferences.getString(KEY_SAVED_URL, "")
|
||||||
|
if (!savedUrl.isNullOrEmpty()) {
|
||||||
|
urlInput.setText(savedUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置状态栏为透明,使系统自动使用默认的颜色
|
// 设置状态栏为透明,使系统自动使用默认的颜色
|
||||||
|
|
@ -84,6 +84,10 @@ class MainActivity : AppCompatActivity() {
|
||||||
});
|
});
|
||||||
""".trimIndent(), null
|
""".trimIndent(), null
|
||||||
)
|
)
|
||||||
|
// 隐藏输入框和按钮
|
||||||
|
urlInput.visibility = View.GONE
|
||||||
|
loadUrlButton.visibility = View.GONE
|
||||||
|
webView.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,89 +125,19 @@ class MainActivity : AppCompatActivity() {
|
||||||
url = "https://$url"
|
url = "https://$url"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 保存用户输入的 URL 到 SharedPreferences
|
||||||
|
with(sharedPreferences.edit()) {
|
||||||
|
putString(KEY_SAVED_URL, url)
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
|
||||||
// 加载用户输入的 URL
|
// 加载用户输入的 URL
|
||||||
webView.loadUrl(url)
|
webView.loadUrl(url)
|
||||||
|
|
||||||
// 切换视图:隐藏 URL 输入部分并显示 WebView
|
|
||||||
urlInputLayout.visibility = View.GONE
|
|
||||||
webView.visibility = View.VISIBLE
|
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(this, "Please enter a valid URL", Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, "Please enter a valid URL", Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 方法:检查是否具有存储权限
|
// 此时不再需要权限检查方法
|
||||||
private fun hasStoragePermission(): Boolean {
|
}
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
||||||
ContextCompat.checkSelfPermission(
|
|
||||||
this,
|
|
||||||
android.Manifest.permission.READ_MEDIA_IMAGES
|
|
||||||
) == PackageManager.PERMISSION_GRANTED
|
|
||||||
} else {
|
|
||||||
ContextCompat.checkSelfPermission(
|
|
||||||
this,
|
|
||||||
android.Manifest.permission.READ_EXTERNAL_STORAGE
|
|
||||||
) == PackageManager.PERMISSION_GRANTED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 方法:请求存储权限
|
|
||||||
private fun requestStoragePermission() {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
||||||
if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.READ_MEDIA_IMAGES)) {
|
|
||||||
showPermissionRationale(android.Manifest.permission.READ_MEDIA_IMAGES)
|
|
||||||
} else {
|
|
||||||
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.READ_MEDIA_IMAGES), 1)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.READ_EXTERNAL_STORAGE)) {
|
|
||||||
showPermissionRationale(android.Manifest.permission.READ_EXTERNAL_STORAGE)
|
|
||||||
} else {
|
|
||||||
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE), 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 方法:显示权限请求解释
|
|
||||||
private fun showPermissionRationale(permission: String) {
|
|
||||||
AlertDialog.Builder(this)
|
|
||||||
.setTitle("Permission Required")
|
|
||||||
.setMessage("This app requires access to your storage to select images. Please grant the permission.")
|
|
||||||
.setPositiveButton("OK") { _, _ ->
|
|
||||||
ActivityCompat.requestPermissions(this, arrayOf(permission), 1)
|
|
||||||
}
|
|
||||||
.setNegativeButton("Cancel") { dialog, _ ->
|
|
||||||
dialog.dismiss()
|
|
||||||
}
|
|
||||||
.create()
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理权限请求结果
|
|
||||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
|
||||||
if (requestCode == 1) {
|
|
||||||
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
|
|
||||||
Toast.makeText(this, "Read permission granted", Toast.LENGTH_SHORT).show()
|
|
||||||
} else {
|
|
||||||
Toast.makeText(this, "Read permission denied", Toast.LENGTH_SHORT).show()
|
|
||||||
// 引导用户前往设置手动开启权限
|
|
||||||
AlertDialog.Builder(this)
|
|
||||||
.setTitle("Permission Denied")
|
|
||||||
.setMessage("Storage permission is required for this app. Please allow it from settings.")
|
|
||||||
.setPositiveButton("Settings") { _, _ ->
|
|
||||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
|
|
||||||
val uri = Uri.fromParts("package", packageName, null)
|
|
||||||
intent.data = uri
|
|
||||||
startActivity(intent)
|
|
||||||
}
|
|
||||||
.setNegativeButton("Cancel") { dialog, _ ->
|
|
||||||
dialog.dismiss()
|
|
||||||
}
|
|
||||||
.create()
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue