更新版本
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2
.idea/deploymentTargetSelector.xml
generated
2
.idea/deploymentTargetSelector.xml
generated
@@ -4,7 +4,7 @@
|
|||||||
<selectionStates>
|
<selectionStates>
|
||||||
<SelectionState runConfigName="app">
|
<SelectionState runConfigName="app">
|
||||||
<option name="selectionMode" value="DROPDOWN" />
|
<option name="selectionMode" value="DROPDOWN" />
|
||||||
<DropdownSelection timestamp="2026-08-10T02:36:52.136106800Z">
|
<DropdownSelection timestamp="2026-08-14T02:57:51.212958400Z">
|
||||||
<Target type="DEFAULT_BOOT">
|
<Target type="DEFAULT_BOOT">
|
||||||
<handle>
|
<handle>
|
||||||
<DeviceId pluginId="PhysicalDevice" identifier="serial=D122222104A9" />
|
<DeviceId pluginId="PhysicalDevice" identifier="serial=D122222104A9" />
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".CKApp"
|
android:name=".CKApp"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@@ -278,7 +281,7 @@
|
|||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="com.ck.ckcollar.app.fileprovider"
|
android:authorities="${applicationId}.fileprovider"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:grantUriPermissions="true">
|
android:grantUriPermissions="true">
|
||||||
<meta-data
|
<meta-data
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
package com.ck.ckcollar.app.model
|
package com.ck.ckcollar.app.model
|
||||||
|
|
||||||
class UpdateModel : CkBaseModel(){
|
class UpdateModel : CkBaseModel(){
|
||||||
//{"androidVersion":1,"content":"","iosVersion":1,"isForce":false}
|
var content: String? = ""
|
||||||
|
var downloadUrl: String? = ""
|
||||||
var androidVersion : Int = 0
|
var hasUpdate: Boolean = false
|
||||||
var iosVersion : Int = 0
|
var isForce: Boolean = false
|
||||||
var isForce : Boolean = false
|
var versionCode: Int = 0
|
||||||
var content : String? = ""
|
var versionName: String? = ""
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,44 +1,62 @@
|
|||||||
package com.ck.ckcollar.app.ui.act.home
|
package com.ck.ckcollar.app.ui.act.home
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Color
|
import android.content.pm.PackageManager
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
import android.view.MenuItem
|
import android.provider.Settings
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.WindowInsets
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.viewpager2.widget.ViewPager2
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.content.FileProvider
|
||||||
import com.ck.ckcollar.app.R
|
import com.ck.ckcollar.app.R
|
||||||
import com.ck.ckcollar.app.databinding.ActivityMainBinding
|
import com.ck.ckcollar.app.databinding.ActivityMainBinding
|
||||||
import com.ck.ckcollar.app.databinding.FragmentHomeBinding
|
|
||||||
import com.ck.ckcollar.app.model.CustomerStatusModel
|
|
||||||
import com.ck.ckcollar.app.model.UpdateModel
|
import com.ck.ckcollar.app.model.UpdateModel
|
||||||
import com.ck.ckcollar.app.ui.act.home.adapter.MainFragmentAdapter
|
import com.ck.ckcollar.app.ui.act.home.adapter.MainFragmentAdapter
|
||||||
import com.ck.ckcollar.app.ui.act.home.fragment.HealthFragment
|
import com.ck.ckcollar.app.ui.act.home.fragment.HealthFragment
|
||||||
import com.ck.ckcollar.app.ui.act.home.fragment.HomeFragment
|
import com.ck.ckcollar.app.ui.act.home.fragment.HomeFragment
|
||||||
import com.ck.ckcollar.app.ui.act.home.fragment.MineFragment
|
import com.ck.ckcollar.app.ui.act.home.fragment.MineFragment
|
||||||
import com.ck.ckcollar.app.ui.act.home.fragment.ShopFragment
|
import com.ck.ckcollar.app.ui.act.home.fragment.ShopFragment
|
||||||
import com.ck.ckcollar.app.ui.base.CKBaseActivity
|
|
||||||
import com.ck.ckcollar.app.ui.base.CKBaseFragment
|
import com.ck.ckcollar.app.ui.base.CKBaseFragment
|
||||||
import com.ck.ckcollar.app.ui.base.CKLHBaseActivity
|
import com.ck.ckcollar.app.ui.base.CKLHBaseActivity
|
||||||
import com.ck.ckcollar.app.ui.dialog.CKUpdateAlertDialog
|
import com.ck.ckcollar.app.ui.dialog.CKUpdateAlertDialog
|
||||||
|
import com.ck.ckcollar.app.utils.AppUpdateDownloader
|
||||||
import com.ck.ckcollar.app.utils.networkone.ICallback
|
import com.ck.ckcollar.app.utils.networkone.ICallback
|
||||||
import com.ck.ckcollar.app.utils.networkone.TTHttpClient
|
import com.ck.ckcollar.app.utils.networkone.TTHttpClient
|
||||||
import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam
|
import com.ck.ckcollar.app.utils.networkone.model.TTRequestParam
|
||||||
import com.cyclone.shadowsocks.ui.frg.TTBaseFragment
|
|
||||||
import com.google.android.material.navigation.NavigationBarView
|
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
|
import java.io.File
|
||||||
import com.tt.kit.base.TTBaseActivity
|
|
||||||
import com.tt.kit.utils.TTUtils
|
|
||||||
|
|
||||||
|
|
||||||
class MainActivity : CKLHBaseActivity(),View.OnClickListener {
|
class MainActivity : CKLHBaseActivity(),View.OnClickListener {
|
||||||
private var lastBackPressedAt = 0L
|
private var lastBackPressedAt = 0L
|
||||||
|
private var pendingUpdate: UpdateModel? = null
|
||||||
|
private var updateDialog: CKUpdateAlertDialog? = null
|
||||||
|
private var pendingApk: File? = null
|
||||||
|
|
||||||
|
private val notificationPermissionLauncher = registerForActivityResult(
|
||||||
|
ActivityResultContracts.RequestPermission()
|
||||||
|
) { granted ->
|
||||||
|
if (granted) {
|
||||||
|
pendingUpdate?.let(::startUpdateDownload)
|
||||||
|
} else {
|
||||||
|
toast(getString(R.string.notification_permission_required))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val installPermissionLauncher = registerForActivityResult(
|
||||||
|
ActivityResultContracts.StartActivityForResult()
|
||||||
|
) {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || packageManager.canRequestPackageInstalls()) {
|
||||||
|
pendingApk?.let(::installApk)
|
||||||
|
} else {
|
||||||
|
toast(getString(R.string.install_permission_required))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lateinit var mainBinding: ActivityMainBinding
|
lateinit var mainBinding: ActivityMainBinding
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@@ -156,7 +174,7 @@ class MainActivity : CKLHBaseActivity(),View.OnClickListener {
|
|||||||
// }
|
// }
|
||||||
// }).show()
|
// }).show()
|
||||||
|
|
||||||
// checkUpdate()
|
checkUpdate()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,15 +225,16 @@ class MainActivity : CKLHBaseActivity(),View.OnClickListener {
|
|||||||
TTHttpClient.get(this,"更新", TTRequestParam(),object : ICallback{
|
TTHttpClient.get(this,"更新", TTRequestParam(),object : ICallback{
|
||||||
override fun onSuccess(data: String) {
|
override fun onSuccess(data: String) {
|
||||||
|
|
||||||
var mode = Gson().fromJson<UpdateModel>(data,UpdateModel::class.java)
|
val model = Gson().fromJson<UpdateModel>(data, UpdateModel::class.java)
|
||||||
|
|
||||||
if (mode.androidVersion != TTUtils.getVersionCode(this@MainActivity)){
|
if (model.hasUpdate) {
|
||||||
CKUpdateAlertDialog(this@MainActivity,mode
|
val updateContent = model.content.orEmpty().replace("\\n", "\n")
|
||||||
.content!!,mode.isForce,object : CKUpdateAlertDialog.AlertClickListener{
|
updateDialog = CKUpdateAlertDialog(this@MainActivity, updateContent,
|
||||||
|
model.isForce, object : CKUpdateAlertDialog.AlertClickListener{
|
||||||
override fun onBack(isConfirm: Boolean) {
|
override fun onBack(isConfirm: Boolean) {
|
||||||
|
if (isConfirm) requestUpdateDownload(model)
|
||||||
}
|
}
|
||||||
}).show()
|
}).also { it.show() }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -226,6 +245,87 @@ class MainActivity : CKLHBaseActivity(),View.OnClickListener {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun requestUpdateDownload(model: UpdateModel) {
|
||||||
|
if (model.downloadUrl.isNullOrBlank()) {
|
||||||
|
toast(getString(R.string.update_url_invalid))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pendingUpdate = model
|
||||||
|
if (!model.isForce && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
|
||||||
|
ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) !=
|
||||||
|
PackageManager.PERMISSION_GRANTED
|
||||||
|
) {
|
||||||
|
notificationPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
startUpdateDownload(model)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startUpdateDownload(model: UpdateModel) {
|
||||||
|
pendingUpdate = null
|
||||||
|
if (model.isForce) {
|
||||||
|
updateDialog?.showDownloadProgress()
|
||||||
|
} else {
|
||||||
|
updateDialog?.dismiss()
|
||||||
|
updateDialog = null
|
||||||
|
}
|
||||||
|
AppUpdateDownloader(applicationContext).download(
|
||||||
|
model.downloadUrl.orEmpty(),
|
||||||
|
showNotification = !model.isForce,
|
||||||
|
callback = object : AppUpdateDownloader.Callback {
|
||||||
|
override fun onProgress(percent: Int) {
|
||||||
|
runOnUiThread { updateDialog?.updateProgress(percent) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onComplete(apkFile: File) {
|
||||||
|
runOnUiThread {
|
||||||
|
if (model.isForce) {
|
||||||
|
updateDialog?.dismiss()
|
||||||
|
updateDialog = null
|
||||||
|
}
|
||||||
|
pendingApk = apkFile
|
||||||
|
installApk(apkFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(message: String) {
|
||||||
|
runOnUiThread {
|
||||||
|
updateDialog?.showDownloadError()
|
||||||
|
toast(getString(R.string.update_download_failed, message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun installApk(apkFile: File) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
|
||||||
|
!packageManager.canRequestPackageInstalls()
|
||||||
|
) {
|
||||||
|
toast(getString(R.string.install_permission_required))
|
||||||
|
installPermissionLauncher.launch(
|
||||||
|
Intent(
|
||||||
|
Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,
|
||||||
|
Uri.parse("package:$packageName")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pendingApk = null
|
||||||
|
val apkUri = FileProvider.getUriForFile(
|
||||||
|
this,
|
||||||
|
"$packageName.fileprovider",
|
||||||
|
apkFile
|
||||||
|
)
|
||||||
|
startActivity(
|
||||||
|
Intent(Intent.ACTION_VIEW).apply {
|
||||||
|
setDataAndType(apkUri, "application/vnd.android.package-archive")
|
||||||
|
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val EXTRA_SHOW_HOME = "extra_show_home"
|
const val EXTRA_SHOW_HOME = "extra_show_home"
|
||||||
private const val EXIT_INTERVAL_MS = 2_000L
|
private const val EXIT_INTERVAL_MS = 2_000L
|
||||||
|
|||||||
@@ -357,15 +357,17 @@ class OrderActivity : CKBaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailed(code: String, msg: String) {
|
override fun onFailed(code: String, msg: String) {
|
||||||
|
|
||||||
toast(msg)
|
toast(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailed(code: String, msg: String, data: String) {
|
||||||
|
onFailed(code, msg)
|
||||||
//原有【不足】的字符串判断条件
|
//原有【不足】的字符串判断条件
|
||||||
if (code.equals("502")){
|
if (code == "502") {
|
||||||
var a = 0;
|
val orderId = JSONObject(data).optInt("orderId")
|
||||||
// toActivity(
|
if (orderId > 0) {
|
||||||
// MyOrderActivity::class.java,
|
model.orderId = orderId
|
||||||
// DataCollection().apply { add(Data("pos", "1")) })
|
}
|
||||||
// finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -19,10 +19,13 @@ class CKUpdateAlertDialog(
|
|||||||
var alertClickListener: AlertClickListener
|
var alertClickListener: AlertClickListener
|
||||||
) : TTBaseDialog(mContext){
|
) : TTBaseDialog(mContext){
|
||||||
|
|
||||||
|
private var binding: DialogUpdateAlertBinding? = null
|
||||||
|
|
||||||
override fun show() {
|
override fun show() {
|
||||||
try {
|
try {
|
||||||
var dialogAlertBinding =
|
val dialogAlertBinding =
|
||||||
DialogUpdateAlertBinding.inflate(LayoutInflater.from(mContext))
|
DialogUpdateAlertBinding.inflate(LayoutInflater.from(mContext))
|
||||||
|
binding = dialogAlertBinding
|
||||||
|
|
||||||
dialogAlertBinding.textAlert.text = alertText
|
dialogAlertBinding.textAlert.text = alertText
|
||||||
if (isForce){
|
if (isForce){
|
||||||
@@ -39,8 +42,6 @@ class CKUpdateAlertDialog(
|
|||||||
//dialogView.findViewById(R.id.photo).setVisibility(View.GONE);
|
//dialogView.findViewById(R.id.photo).setVisibility(View.GONE);
|
||||||
dialogAlertBinding.btnConfirm.setOnClickListener(object : View.OnClickListener {
|
dialogAlertBinding.btnConfirm.setOnClickListener(object : View.OnClickListener {
|
||||||
override fun onClick(v: View?) {
|
override fun onClick(v: View?) {
|
||||||
// TODO Auto-generated method stub
|
|
||||||
cancel()
|
|
||||||
alertClickListener.onBack(true)
|
alertClickListener.onBack(true)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -55,8 +56,36 @@ class CKUpdateAlertDialog(
|
|||||||
setCancelable(false)
|
setCancelable(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun showDownloadProgress() {
|
||||||
|
binding?.apply {
|
||||||
|
progressContainer.visibility = View.VISIBLE
|
||||||
|
btnConfirm.visibility = View.GONE
|
||||||
|
btnCenlel.visibility = View.GONE
|
||||||
|
textAlert.visibility = View.GONE
|
||||||
|
title.text = mContext.getString(com.ck.ckcollar.app.R.string.update_downloading, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateProgress(progress: Int) {
|
||||||
|
binding?.apply {
|
||||||
|
updateProgress.progress = progress
|
||||||
|
progressText.text = "$progress%"
|
||||||
|
title.text = mContext.getString(com.ck.ckcollar.app.R.string.update_downloading, progress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showDownloadError() {
|
||||||
|
binding?.apply {
|
||||||
|
progressContainer.visibility = View.GONE
|
||||||
|
btnConfirm.visibility = View.VISIBLE
|
||||||
|
btnCenlel.visibility = if (isForce) View.GONE else View.VISIBLE
|
||||||
|
textAlert.visibility = View.VISIBLE
|
||||||
|
title.text = mContext.getString(com.ck.ckcollar.app.R.string.update_content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
interface AlertClickListener {
|
interface AlertClickListener {
|
||||||
fun onBack(isConfirm : Boolean)
|
fun onBack(isConfirm : Boolean)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,5 +2,8 @@ package com.ck.ckcollar.app.utils.networkone
|
|||||||
interface ICallback {
|
interface ICallback {
|
||||||
fun onSuccess(data: String)
|
fun onSuccess(data: String)
|
||||||
fun onFailed(code: String, msg: String)
|
fun onFailed(code: String, msg: String)
|
||||||
|
fun onFailed(code: String, msg: String, data: String) {
|
||||||
|
onFailed(code, msg)
|
||||||
|
}
|
||||||
fun onComplete() {}
|
fun onComplete() {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -491,7 +491,7 @@ fun postJson(
|
|||||||
} else {
|
} else {
|
||||||
activity.runOnUiThread {
|
activity.runOnUiThread {
|
||||||
activity.hiddenProgeassDialog()
|
activity.hiddenProgeassDialog()
|
||||||
iCallback.onFailed(getCode(model), getMessage(model))
|
iCallback.onFailed(getCode(model), getMessage(model), model.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,9 +31,36 @@
|
|||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="10dp"
|
||||||
android:text="更新内容"
|
android:text="更新内容"
|
||||||
android:textColor="@color/textColor"
|
android:textColor="@color/textColor"
|
||||||
android:textSize="16sp"
|
android:textSize="14sp"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/progressContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/updateProgress"
|
||||||
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="8dp"
|
||||||
|
android:max="100"
|
||||||
|
android:progress="0" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/progressText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="0%"
|
||||||
|
android:textColor="@color/textSecondColor"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
<com.ck.ckcollar.app.widget.CKButton
|
<com.ck.ckcollar.app.widget.CKButton
|
||||||
android:id="@+id/btnConfirm"
|
android:id="@+id/btnConfirm"
|
||||||
|
|||||||
@@ -603,4 +603,10 @@
|
|||||||
<string name="input_question">请输入问题</string>
|
<string name="input_question">请输入问题</string>
|
||||||
<string name="pet_note">宠物常识</string>
|
<string name="pet_note">宠物常识</string>
|
||||||
|
|
||||||
|
<string name="update_downloading">正在下载更新 %1$d%%</string>
|
||||||
|
<string name="update_download_failed">更新下载失败:%1$s</string>
|
||||||
|
<string name="update_url_invalid">更新下载地址不可用</string>
|
||||||
|
<string name="notification_permission_required">需要开启通知权限,以便在通知栏显示下载进度</string>
|
||||||
|
<string name="install_permission_required">请允许本应用安装更新,授权后返回即可继续安装</string>
|
||||||
|
<string name="update_content">更新内容</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<paths>
|
<paths>
|
||||||
<!-- 对应 getExternalFilesDir(Environment.DIRECTORY_PICTURES) -->
|
<!-- 对应 getExternalFilesDir(Environment.DIRECTORY_PICTURES) -->
|
||||||
<external-files-path name="my_images" path="Pictures" />
|
<external-files-path name="my_images" path="Pictures" />
|
||||||
|
<external-files-path name="app_updates" path="updates" />
|
||||||
<!-- 对应 getExternalFilesDir(Environment.DIRECTORY_DCIM) -->
|
<!-- 对应 getExternalFilesDir(Environment.DIRECTORY_DCIM) -->
|
||||||
<external-files-path name="dcim" path="DCIM" />
|
<external-files-path name="dcim" path="DCIM" />
|
||||||
<!-- 对应外部存储根目录 -->
|
<!-- 对应外部存储根目录 -->
|
||||||
|
|||||||
Reference in New Issue
Block a user