package com.logship.mobile; import android.app.DownloadManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.os.Environment; import androidx.core.content.FileProvider; import com.getcapacitor.JSObject; import com.getcapacitor.Plugin; import com.getcapacitor.PluginCall; import com.getcapacitor.PluginMethod; import com.getcapacitor.annotation.CapacitorPlugin; import java.io.File; @CapacitorPlugin(name = "AppUpdate") public class AppUpdatePlugin extends Plugin { private DownloadManager downloadManager; private long downloadId = -1; private PluginCall pendingCall; @PluginMethod public void getAppVersion(PluginCall call) { try { PackageInfo pInfo = getContext().getPackageManager().getPackageInfo(getContext().getPackageName(), 0); JSObject ret = new JSObject(); ret.put("versionName", pInfo.versionName); ret.put("versionCode", pInfo.versionCode); call.resolve(ret); } catch (PackageManager.NameNotFoundException e) { call.reject("Could not get app version", e); } } @PluginMethod public void downloadAndInstall(PluginCall call) { String apkUrl = call.getString("url"); if (apkUrl == null || apkUrl.isEmpty()) { call.reject("URL is required"); return; } try { // Delete old APK if exists File oldApk = new File(getContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "app-update.apk"); if (oldApk.exists()) { oldApk.delete(); } downloadManager = (DownloadManager) getContext().getSystemService(Context.DOWNLOAD_SERVICE); DownloadManager.Request request = new DownloadManager.Request(Uri.parse(apkUrl)); request.setTitle("LogShip Mobile Update"); request.setDescription("Downloading update..."); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); request.setDestinationInExternalFilesDir(getContext(), Environment.DIRECTORY_DOWNLOADS, "app-update.apk"); request.setMimeType("application/vnd.android.package-archive"); downloadId = downloadManager.enqueue(request); pendingCall = call; // Register receiver for download complete BroadcastReceiver onComplete = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (downloadId == intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)) { context.unregisterReceiver(this); installApk(); } } }; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { getContext().registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE), Context.RECEIVER_EXPORTED); } else { getContext().registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); } } catch (Exception e) { call.reject("Download failed: " + e.getMessage(), e); } } private void installApk() { try { File apkFile = new File(getContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "app-update.apk"); if (!apkFile.exists()) { if (pendingCall != null) { pendingCall.reject("APK file not found"); pendingCall = null; } return; } Intent intent = new Intent(Intent.ACTION_VIEW); Uri apkUri; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { apkUri = FileProvider.getUriForFile(getContext(), getContext().getPackageName() + ".fileprovider", apkFile); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } else { apkUri = Uri.fromFile(apkFile); } intent.setDataAndType(apkUri, "application/vnd.android.package-archive"); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); getContext().startActivity(intent); if (pendingCall != null) { JSObject ret = new JSObject(); ret.put("success", true); pendingCall.resolve(ret); pendingCall = null; } } catch (Exception e) { if (pendingCall != null) { pendingCall.reject("Install failed: " + e.getMessage(), e); pendingCall = null; } } } }