fix update

This commit is contained in:
Li ZongYing
2024-05-07 17:55:08 +08:00
parent fc83defe31
commit 0286d118ed
11 changed files with 134 additions and 50 deletions
+5
View File
@@ -1,5 +1,10 @@
## 更新日志 ## 更新日志
### v1.9.6(通用)
* 优化在线升级
* 优化可能状态错误的问题
### v1.9.4(通用) ### v1.9.4(通用)
* 修复默认时间不显示问题 * 修复默认时间不显示问题
+10
View File
@@ -12,6 +12,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<application <application
android:name=".MyTvApplication" android:name=".MyTvApplication"
@@ -63,5 +64,14 @@
android:exported="false" /> android:exported="false" />
<meta-data android:name="android.max_aspect" android:value="2.5" /> <meta-data android:name="android.max_aspect" android:value="2.5" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application> </application>
</manifest> </manifest>
@@ -7,14 +7,15 @@ import androidx.fragment.app.DialogFragment
class ConfirmationFragment( class ConfirmationFragment(
private val listener: ConfirmationListener, private val listener: ConfirmationListener,
private val message: String private val message: String,
private val update: Boolean
) : DialogFragment() { ) : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return activity?.let { return activity?.let {
val builder = AlertDialog.Builder(it) val builder = AlertDialog.Builder(it)
builder.setTitle(message) builder.setTitle(message)
if (message != "版本获取失败") { if (update) {
builder.setMessage("确定更新吗?") builder.setMessage("确定更新吗?")
.setPositiveButton( .setPositiveButton(
"确定" "确定"
@@ -27,7 +28,8 @@ class ConfirmationFragment(
listener.onCancel() listener.onCancel()
} }
} else { } else {
builder.setNegativeButton( builder.setMessage("")
.setNegativeButton(
"好的" "好的"
) { _, _ -> ) { _, _ ->
} }
@@ -87,7 +87,7 @@ class SettingFragment : DialogFragment() {
} }
} }
updateManager = UpdateManager(context, this, context.appVersionCode) updateManager = UpdateManager(context, context.appVersionCode)
binding.checkVersion.setOnClickListener( binding.checkVersion.setOnClickListener(
OnClickListenerCheckVersion( OnClickListenerCheckVersion(
activity as MainActivity, activity as MainActivity,
@@ -17,6 +17,7 @@ import android.util.Log
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.PermissionChecker import androidx.core.content.PermissionChecker
import androidx.core.content.PermissionChecker.checkSelfPermission import androidx.core.content.PermissionChecker.checkSelfPermission
import androidx.fragment.app.FragmentActivity
import com.lizongying.mytv.api.ApiClient import com.lizongying.mytv.api.ApiClient
import com.lizongying.mytv.requests.ReleaseRequest import com.lizongying.mytv.requests.ReleaseRequest
import com.lizongying.mytv.requests.ReleaseResponse import com.lizongying.mytv.requests.ReleaseResponse
@@ -28,7 +29,6 @@ import java.io.File
class UpdateManager( class UpdateManager(
private var context: Context, private var context: Context,
private var settingFragment: SettingFragment,
private var versionCode: Long private var versionCode: Long
) : ) :
ConfirmationFragment.ConfirmationListener { ConfirmationFragment.ConfirmationListener {
@@ -44,30 +44,32 @@ class UpdateManager(
} }
CoroutineScope(Dispatchers.Main).launch { CoroutineScope(Dispatchers.Main).launch {
var text = "版本获取失败" var text = "版本获取失败"
var update = false
try { try {
release = releaseRequest.getRelease() release = releaseRequest.getRelease()
Log.i(TAG, "versionCode $versionCode ${release?.version_code}") Log.i(TAG, "versionCode $versionCode ${release?.version_code}")
if (release?.version_code != null) { if (release?.version_code != null) {
text = if (release?.version_code!! >= versionCode) { if (release?.version_code!! > versionCode) {
"最新版本:${release?.version_name}}" text = "最新版本:${release?.version_name}"
update = true
} else { } else {
"已是最新版本,不需要更新" text = "已是最新版本,不需要更新"
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Error occurred: ${e.message}", e) Log.e(TAG, "Error occurred: ${e.message}", e)
} }
updateUI(text) updateUI(text, update)
} }
} }
private fun updateUI(text: String) { private fun updateUI(text: String, update: Boolean) {
val dialog = ConfirmationFragment(this@UpdateManager, text) val dialog = ConfirmationFragment(this@UpdateManager, text, update)
settingFragment.fragmentManager?.let { dialog.show(it, TAG) } dialog.show((context as FragmentActivity).supportFragmentManager, TAG)
} }
private fun haveStoragePermission(): Boolean { private fun haveStoragePermission(): Boolean {
if (Build.VERSION.SDK_INT >= 23) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(context, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) if (checkSelfPermission(context, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
=== PermissionChecker.PERMISSION_GRANTED === PermissionChecker.PERMISSION_GRANTED
) { ) {
@@ -90,23 +92,31 @@ class UpdateManager(
private fun startDownload(release: ReleaseResponse) { private fun startDownload(release: ReleaseResponse) {
val apkFileName = "my-tv-${release.version_name}.apk" val packageInstaller = context.packageManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!packageInstaller.canRequestPackageInstalls()) {
}
}
val apkName = "my-tv"
val apkFileName = "$apkName-${release.version_name}.apk"
Log.i(TAG, "apkFileName $apkFileName") Log.i(TAG, "apkFileName $apkFileName")
val downloadManager = val downloadManager =
context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val request = val request =
Request(Uri.parse("${ApiClient.HOST}/release/download/${release.version_name}/my-tv-${release.version_name}.apk")) Request(Uri.parse("${ApiClient.DOWNLOAD_HOST}${release.version_name}/$apkName-${release.version_name}.apk"))
Log.i( Log.i(
TAG, TAG,
"url ${Uri.parse("${ApiClient.HOST}/release/download/${release.version_name}/my-tv-0-${release.version_name}.apk")}" "url ${Uri.parse("${ApiClient.DOWNLOAD_HOST}${release.version_name}/$apkName-${release.version_name}.apk")}"
) )
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.mkdirs() context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.mkdirs()
Log.i(TAG, "save dir ${Environment.DIRECTORY_DOWNLOADS}")
request.setDestinationInExternalFilesDir( request.setDestinationInExternalFilesDir(
context, context,
Environment.DIRECTORY_DOWNLOADS, Environment.DIRECTORY_DOWNLOADS,
apkFileName apkFileName
) )
request.setTitle("${settingFragment.resources.getString(R.string.app_name)} ${release.version_name}") request.setTitle("${context.resources.getString(R.string.app_name)} ${release.version_name}")
request.setNotificationVisibility(Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) request.setNotificationVisibility(Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
request.setAllowedOverRoaming(false) request.setAllowedOverRoaming(false)
request.setMimeType("application/vnd.android.package-archive") request.setMimeType("application/vnd.android.package-archive")
@@ -184,27 +194,73 @@ class UpdateManager(
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
val reference = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) val reference = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
Log.i(TAG, "reference $reference") Log.i(TAG, "reference $reference")
val progress = intent.getIntExtra("progress", 0)
Log.i(TAG, "progress $progress")
// 检查是否是我们发起的下载
if (reference == downloadReference) { if (reference == downloadReference) {
// 下载完成,触发安装 val downloadManager =
context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val query = DownloadManager.Query().setFilterById(downloadReference)
val cursor = downloadManager.query(query)
if (cursor != null && cursor.moveToFirst()) {
val statusIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)
if (statusIndex < 0) {
Log.i(TAG, "Download failure")
return
}
val status = cursor.getInt(statusIndex)
val progressIndex =
cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)
if (progressIndex < 0) {
Log.i(TAG, "Download failure")
return
}
val progress = cursor.getInt(progressIndex)
val totalSizeIndex =
cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)
val totalSize = cursor.getInt(totalSizeIndex)
cursor.close()
when (status) {
DownloadManager.STATUS_SUCCESSFUL -> {
installNewVersion() installNewVersion()
} }
DownloadManager.STATUS_FAILED -> {
// Handle download failure
Log.i(TAG, "Download failure")
}
else -> {
// Update UI with download progress
val percentage = progress * 100 / totalSize
Log.i(TAG, "Download progress: $percentage%")
}
}
}
}
} }
private fun installNewVersion() { private fun installNewVersion() {
val installIntent = Intent(Intent.ACTION_VIEW) val apkFile = File(
val apkUri = Uri.fromFile( context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
apkFileName apkFileName
) )
) Log.i(TAG, "apkFile $apkFile")
installIntent.setDataAndType(apkUri, "application/vnd.android.package-archive")
installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) if (apkFile.exists()) {
val apkUri = Uri.parse("file://$apkFile")
Log.i(TAG, "apkUri $apkUri")
val installIntent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(apkUri, "application/vnd.android.package-archive")
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(installIntent) context.startActivity(installIntent)
} else {
Log.e(TAG, "APK file does not exist!")
}
} }
} }
+20 -1
View File
@@ -2,12 +2,15 @@ package com.lizongying.mytv
import android.content.res.Resources import android.content.res.Resources
import android.os.Build import android.os.Build
import android.util.Log
import android.util.TypedValue import android.util.TypedValue
import com.google.gson.Gson import com.google.gson.Gson
import com.lizongying.mytv.api.TimeResponse import com.lizongying.mytv.api.TimeResponse
import com.lizongying.mytv.requests.Request import com.lizongying.mytv.requests.Request
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import okhttp3.Interceptor
import okhttp3.Response
import java.io.IOException import java.io.IOException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
@@ -47,6 +50,20 @@ object Utils {
} }
} }
class RetryInterceptor(private val maxRetry: Int) : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
var response = chain.proceed(request)
var tryCount = 0
while (!response.isSuccessful && tryCount < maxRetry) {
tryCount++
response = chain.proceed(request)
}
return response
}
}
/** /**
* 从服务器获取时间戳 * 从服务器获取时间戳
* @return Long 时间戳 * @return Long 时间戳
@@ -55,7 +72,9 @@ object Utils {
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
val client = okhttp3.OkHttpClient.Builder() val client = okhttp3.OkHttpClient.Builder()
.connectTimeout(500, java.util.concurrent.TimeUnit.MILLISECONDS) .connectTimeout(500, java.util.concurrent.TimeUnit.MILLISECONDS)
.readTimeout(1, java.util.concurrent.TimeUnit.SECONDS).build() .readTimeout(1, java.util.concurrent.TimeUnit.SECONDS)
.addInterceptor(RetryInterceptor(3))
.build()
val request = okhttp3.Request.Builder() val request = okhttp3.Request.Builder()
.url("https://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp") .url("https://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp")
.build() .build()
@@ -173,6 +173,7 @@ class ApiClient {
} }
companion object { companion object {
const val HOST = "https://gitee.com/lizongying/my-tv/" const val HOST = "https://gitee.com/lizongying/my-tv/raw/"
const val DOWNLOAD_HOST = "https://gitee.com/lizongying/my-tv/releases/download/"
} }
} }
@@ -1,12 +0,0 @@
package com.lizongying.mytv.api
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Path
interface ReleaseService {
@GET("my-tv/v2/release/{name}")
fun getRelease(
@Path("name") date: String = "2",
): Call<ReleaseV2>
}
@@ -4,7 +4,7 @@ import retrofit2.Call
import retrofit2.http.GET import retrofit2.http.GET
interface ReleaseService { interface ReleaseService {
@GET("/raw/JELLY_BEAN_MR1/version.json") @GET("JELLY_BEAN_MR1/version.json")
fun getRelease( fun getRelease(
): Call<ReleaseResponse> ): Call<ReleaseResponse>
} }
+3
View File
@@ -0,0 +1,3 @@
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="." />
</paths>
+1 -1
View File
@@ -1 +1 @@
{"version_code": 17368064, "version_name": "v1.9.4"} {"version_code": 17368576, "version_name": "v1.9.6"}