更新版本
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>
|
||||
<SelectionState runConfigName="app">
|
||||
<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">
|
||||
<handle>
|
||||
<DeviceId pluginId="PhysicalDevice" identifier="serial=D122222104A9" />
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
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
|
||||
android:name=".CKApp"
|
||||
android:allowBackup="true"
|
||||
@@ -278,7 +281,7 @@
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="com.ck.ckcollar.app.fileprovider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package com.ck.ckcollar.app.model
|
||||
|
||||
class UpdateModel : CkBaseModel(){
|
||||
//{"androidVersion":1,"content":"","iosVersion":1,"isForce":false}
|
||||
|
||||
var androidVersion : Int = 0
|
||||
var iosVersion : Int = 0
|
||||
var isForce : Boolean = false
|
||||
var content : String? = ""
|
||||
|
||||
var content: String? = ""
|
||||
var downloadUrl: String? = ""
|
||||
var hasUpdate: Boolean = false
|
||||
var isForce: Boolean = false
|
||||
var versionCode: Int = 0
|
||||
var versionName: String? = ""
|
||||
}
|
||||
@@ -1,44 +1,62 @@
|
||||
package com.ck.ckcollar.app.ui.act.home
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.SystemClock
|
||||
import android.view.MenuItem
|
||||
import android.provider.Settings
|
||||
import android.view.View
|
||||
import android.view.WindowInsets
|
||||
import android.widget.TextView
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import com.ck.ckcollar.app.R
|
||||
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.ui.act.home.adapter.MainFragmentAdapter
|
||||
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.MineFragment
|
||||
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.CKLHBaseActivity
|
||||
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.TTHttpClient
|
||||
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.tt.kit.base.TTBaseActivity
|
||||
import com.tt.kit.utils.TTUtils
|
||||
import java.io.File
|
||||
|
||||
|
||||
class MainActivity : CKLHBaseActivity(),View.OnClickListener {
|
||||
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
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -156,7 +174,7 @@ class MainActivity : CKLHBaseActivity(),View.OnClickListener {
|
||||
// }
|
||||
// }).show()
|
||||
|
||||
// checkUpdate()
|
||||
checkUpdate()
|
||||
|
||||
}
|
||||
|
||||
@@ -207,15 +225,16 @@ class MainActivity : CKLHBaseActivity(),View.OnClickListener {
|
||||
TTHttpClient.get(this,"更新", TTRequestParam(),object : ICallback{
|
||||
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)){
|
||||
CKUpdateAlertDialog(this@MainActivity,mode
|
||||
.content!!,mode.isForce,object : CKUpdateAlertDialog.AlertClickListener{
|
||||
if (model.hasUpdate) {
|
||||
val updateContent = model.content.orEmpty().replace("\\n", "\n")
|
||||
updateDialog = CKUpdateAlertDialog(this@MainActivity, updateContent,
|
||||
model.isForce, object : CKUpdateAlertDialog.AlertClickListener{
|
||||
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 {
|
||||
const val EXTRA_SHOW_HOME = "extra_show_home"
|
||||
private const val EXIT_INTERVAL_MS = 2_000L
|
||||
|
||||
@@ -357,15 +357,17 @@ class OrderActivity : CKBaseActivity() {
|
||||
}
|
||||
|
||||
override fun onFailed(code: String, msg: String) {
|
||||
|
||||
toast(msg)
|
||||
}
|
||||
|
||||
override fun onFailed(code: String, msg: String, data: String) {
|
||||
onFailed(code, msg)
|
||||
//原有【不足】的字符串判断条件
|
||||
if (code.equals("502")){
|
||||
var a = 0;
|
||||
// toActivity(
|
||||
// MyOrderActivity::class.java,
|
||||
// DataCollection().apply { add(Data("pos", "1")) })
|
||||
// finish()
|
||||
if (code == "502") {
|
||||
val orderId = JSONObject(data).optInt("orderId")
|
||||
if (orderId > 0) {
|
||||
model.orderId = orderId
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -19,10 +19,13 @@ class CKUpdateAlertDialog(
|
||||
var alertClickListener: AlertClickListener
|
||||
) : TTBaseDialog(mContext){
|
||||
|
||||
private var binding: DialogUpdateAlertBinding? = null
|
||||
|
||||
override fun show() {
|
||||
try {
|
||||
var dialogAlertBinding =
|
||||
val dialogAlertBinding =
|
||||
DialogUpdateAlertBinding.inflate(LayoutInflater.from(mContext))
|
||||
binding = dialogAlertBinding
|
||||
|
||||
dialogAlertBinding.textAlert.text = alertText
|
||||
if (isForce){
|
||||
@@ -39,8 +42,6 @@ class CKUpdateAlertDialog(
|
||||
//dialogView.findViewById(R.id.photo).setVisibility(View.GONE);
|
||||
dialogAlertBinding.btnConfirm.setOnClickListener(object : View.OnClickListener {
|
||||
override fun onClick(v: View?) {
|
||||
// TODO Auto-generated method stub
|
||||
cancel()
|
||||
alertClickListener.onBack(true)
|
||||
}
|
||||
})
|
||||
@@ -55,6 +56,34 @@ class CKUpdateAlertDialog(
|
||||
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 {
|
||||
fun onBack(isConfirm : Boolean)
|
||||
|
||||
@@ -2,5 +2,8 @@ package com.ck.ckcollar.app.utils.networkone
|
||||
interface ICallback {
|
||||
fun onSuccess(data: String)
|
||||
fun onFailed(code: String, msg: String)
|
||||
fun onFailed(code: String, msg: String, data: String) {
|
||||
onFailed(code, msg)
|
||||
}
|
||||
fun onComplete() {}
|
||||
}
|
||||
|
||||
@@ -491,7 +491,7 @@ fun postJson(
|
||||
} else {
|
||||
activity.runOnUiThread {
|
||||
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:text="更新内容"
|
||||
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
|
||||
android:id="@+id/btnConfirm"
|
||||
|
||||
@@ -603,4 +603,10 @@
|
||||
<string name="input_question">请输入问题</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>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<paths>
|
||||
<!-- 对应 getExternalFilesDir(Environment.DIRECTORY_PICTURES) -->
|
||||
<external-files-path name="my_images" path="Pictures" />
|
||||
<external-files-path name="app_updates" path="updates" />
|
||||
<!-- 对应 getExternalFilesDir(Environment.DIRECTORY_DCIM) -->
|
||||
<external-files-path name="dcim" path="DCIM" />
|
||||
<!-- 对应外部存储根目录 -->
|
||||
|
||||
Reference in New Issue
Block a user