Suggest update on play store instead of live

This commit is contained in:
MartinBraquet
2026-01-19 13:49:18 +01:00
parent 94298e4609
commit 218de89583
4 changed files with 132 additions and 79 deletions

View File

@@ -19,6 +19,12 @@ import com.getcapacitor.BridgeActivity;
import com.getcapacitor.BridgeWebViewClient;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginHandle;
import com.google.android.play.core.appupdate.AppUpdateInfo;
import com.google.android.play.core.appupdate.AppUpdateManager;
import com.google.android.play.core.appupdate.AppUpdateManagerFactory;
import com.google.android.play.core.appupdate.AppUpdateOptions;
import com.google.android.play.core.install.model.AppUpdateType;
import com.google.android.play.core.install.model.UpdateAvailability;
import org.json.JSONException;
import org.json.JSONObject;
@@ -27,46 +33,6 @@ import ee.forgr.capacitor.social.login.GoogleProvider;
import ee.forgr.capacitor.social.login.ModifiedMainActivityForSocialLoginPlugin;
import ee.forgr.capacitor.social.login.SocialLoginPlugin;
//import android.app.NotificationChannel;
//import android.app.NotificationManager;
//import android.os.Build;
//import com.google.firebase.messaging.RemoteMessage;
//import com.capacitorjs.plugins.pushnotifications.MessagingService;
//public class MyMessagingService extends MessagingService {
//
// @Override
// public void onMessageReceived(RemoteMessage remoteMessage) {
// // TODO(developer): Handle FCM messages here.
// // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
// Log.d(TAG, "From: " + remoteMessage.getFrom());
//
// // Check if message contains a data payload.
// if (remoteMessage.getData().size() > 0) {
// Log.d(TAG, "Message data payload: " + remoteMessage.getData());
//
// if (/* Check if data needs to be processed by long running job */ true) {
// // For long-running tasks (10 seconds or more) use WorkManager.
// scheduleJob();
// } else {
// // Handle message within 10 seconds
// handleNow();
// }
//
// }
//
// // Check if message contains a notification payload.
// if (remoteMessage.getNotification() != null) {
// Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
// }
//
// // Also if you intend on generating your own notifications as a result of a received FCM
// // message, here is where that should be initiated. See sendNotification method below.
// }
//}
public class MainActivity extends BridgeActivity implements ModifiedMainActivityForSocialLoginPlugin {
// Declare this at class level
@@ -143,6 +109,9 @@ public class MainActivity extends BridgeActivity implements ModifiedMainActivity
// }});
askNotificationPermission();
appUpdateManager = AppUpdateManagerFactory.create(this);
checkForUpdates();
}
@Override
@@ -169,5 +138,69 @@ public class MainActivity extends BridgeActivity implements ModifiedMainActivity
@Override
public void IHaveModifiedTheMainActivityForTheUseWithSocialLoginPlugin() {
}
private static final int UPDATE_REQUEST_CODE = 500;
private AppUpdateManager appUpdateManager;
private static final String TAG = "MainActivity";
private void checkForUpdates() {
appUpdateManager.getAppUpdateInfo()
.addOnSuccessListener(appUpdateInfo -> {
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE) {
if (appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
startImmediateUpdate(appUpdateInfo);
} else if (appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {
startFlexibleUpdate(appUpdateInfo);
}
}
})
.addOnFailureListener(exception -> {
// Handle error - log it
Log.e(TAG, "Failed to check For Updates", exception);
});
}
private void startImmediateUpdate(AppUpdateInfo appUpdateInfo) {
AppUpdateOptions options = AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build();
appUpdateManager.startUpdateFlow(appUpdateInfo, this, options)
.addOnSuccessListener(result -> {
Log.i(TAG, "Immediate update started successfully");
})
.addOnFailureListener(exception -> {
Log.e(TAG, "Failed to start immediate update", exception);
});
}
private void startFlexibleUpdate(AppUpdateInfo appUpdateInfo) {
AppUpdateOptions options = AppUpdateOptions.newBuilder(AppUpdateType.FLEXIBLE).build();
appUpdateManager.startUpdateFlow(appUpdateInfo, this, options)
.addOnSuccessListener(result -> {
Log.i(TAG, "Flexible update started successfully");
})
.addOnFailureListener(exception -> {
Log.e(TAG, "Failed to start flexible update", exception);
});
}
@Override
public void onResume() {
super.onResume();
// Check if an immediate update was interrupted
appUpdateManager.getAppUpdateInfo().addOnSuccessListener(appUpdateInfo -> {
if (appUpdateInfo.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
startImmediateUpdate(appUpdateInfo);
}
});
}
@Override
public void onDestroy() {
super.onDestroy();
appUpdateManager = null;
}
}

View File

@@ -3,14 +3,12 @@ import {PrivateUser} from "common/user"
import {Col} from "web/components/layout/col"
import {HOSTING_ENV, IS_VERCEL} from "common/hosting/constants"
import {Capacitor} from "@capacitor/core"
import {LiveUpdate} from "@capawesome/capacitor-live-update"
import {useEffect, useState} from "react"
import {App} from "@capacitor/app"
import {api} from "web/lib/api"
import {githubRepo} from "common/constants"
import {CustomLink} from "web/components/links"
import {Button} from "web/components/buttons/button"
import {getLiveUpdateInfo} from "web/lib/live-update";
import {useT} from 'web/lib/locale'
export type WebBuild = {
@@ -77,17 +75,19 @@ function useDiagnostics() {
if (Capacitor.isNativePlatform()) {
const appInfo = await App.getInfo()
const bundle = await LiveUpdate.getCurrentBundle().catch(() => {return {bundleId: null}})
const buildInfo = await getLiveUpdateInfo().catch(() => null)
// const bundle = await LiveUpdate.getCurrentBundle().catch(() => {
// return {bundleId: null}
// })
// const buildInfo = await getLiveUpdateInfo().catch(() => null)
diagnostics.android = {
appVersion: appInfo.version,
buildNumber: appInfo.build,
liveUpdate: {
bundleId: bundle?.bundleId,
commitSha: buildInfo?.commitSha,
commitMessage: buildInfo?.commitMessage,
commitDate: buildInfo?.commitDate
}
// liveUpdate: {
// bundleId: bundle?.bundleId,
// commitSha: buildInfo?.commitSha,
// commitMessage: buildInfo?.commitMessage,
// commitDate: buildInfo?.commitDate
// }
}
}
@@ -166,7 +166,7 @@ const LoadedAboutSettings = (props: {
</Col>
}
const WebBuildInfo = (props: {info?: WebBuild}) => {
const WebBuildInfo = (props: { info?: WebBuild }) => {
const {info} = props
if (!info) return
const env = info.environment
@@ -183,7 +183,7 @@ const WebBuildInfo = (props: {info?: WebBuild}) => {
</Col>
}
const AndroidInfo = (props: {info?: Android}) => {
const AndroidInfo = (props: { info?: Android }) => {
const {info} = props
if (!info) return
const sha = info.liveUpdate?.commitSha
@@ -192,14 +192,18 @@ const AndroidInfo = (props: {info?: Android}) => {
<h3>Android (Capacitor / Capawesome)</h3>
<p>App version (Android): {info.appVersion}</p>
<p>Native build number (Android): {info.buildNumber}</p>
<p>Live update build ID (Capawesome): {info.liveUpdate?.bundleId}</p>
<p>Live update commit SHA (Capawesome): <CustomLink href={url}>{sha}</CustomLink></p>
<p>Live update commit message (Capawesome): {info.liveUpdate?.commitMessage}</p>
<p>Live update commit date (Capawesome): {info.liveUpdate?.commitDate}</p>
{info.liveUpdate &&
<>
<p>Live update build ID (Capawesome): {info.liveUpdate?.bundleId}</p>
<p>Live update commit SHA (Capawesome): <CustomLink href={url}>{sha}</CustomLink></p>
<p>Live update commit message (Capawesome): {info.liveUpdate?.commitMessage}</p>
<p>Live update commit date (Capawesome): {info.liveUpdate?.commitDate}</p>
</>
}
</Col>
}
const BackendInfo = (props: {info?: Backend}) => {
const BackendInfo = (props: { info?: Backend }) => {
const {info} = props
if (!info) return
const sha = info.gitSha
@@ -215,7 +219,7 @@ const BackendInfo = (props: {info?: Backend}) => {
</Col>
}
const RuntimeInfo = (props: {info?: Runtime}) => {
const RuntimeInfo = (props: { info?: Runtime }) => {
const {info} = props
if (!info) return
return <Col className={'custom-link'}>

16
web/lib/app-update.ts Normal file
View File

@@ -0,0 +1,16 @@
import {registerPlugin} from '@capacitor/core'
interface AppUpdatePlugin {
checkForUpdate(): Promise<{
updateAvailable: boolean
immediateAllowed: boolean
flexibleAllowed: boolean
availableVersionCode: number
}>
startUpdate(options: { type: 'immediate' | 'flexible' }): Promise<void>
}
const AppUpdate = registerPlugin<AppUpdatePlugin>('AppUpdate')
export default AppUpdate

View File

@@ -18,14 +18,13 @@ import {StatusBar} from '@capacitor/status-bar'
import {App} from '@capacitor/app'
import {useRouter} from "next/navigation"
import {Keyboard} from "@capacitor/keyboard"
import {LiveUpdate} from "@capawesome/capacitor-live-update"
import {IS_VERCEL} from "common/hosting/constants"
import {getLocale, resetCachedLocale} from "web/lib/locale-cookie";
import {getLocale, resetCachedLocale} from "web/lib/locale-cookie"
import {I18nContext} from "web/lib/locale"
if (Capacitor.isNativePlatform()) {
// Only runs on iOS/Android native
// Note sure it's doing anything, though, need to check
// Note sure it's doing anything, though. Need to check
StatusBar.setOverlaysWebView({overlay: false}).catch(console.warn)
// StatusBar.setStyle({style: Style.Light}).catch(console.warn)
@@ -33,23 +32,24 @@ if (Capacitor.isNativePlatform()) {
window.dispatchEvent(new CustomEvent('appBackButton'))
})
App.addListener("resume", async () => {
const newChannelName = 'default'
try {
await LiveUpdate.setChannel({channel: newChannelName})
console.log(`Device channel set to: ${newChannelName}`)
} catch (error) {
console.error('Failed to set channel', error)
}
const {nextBundleId} = await LiveUpdate.sync()
if (nextBundleId) {
// Ask the user if they want to apply the update immediately
const shouldReload = confirm("A new update is available. Would you like to install it?")
if (shouldReload) {
await LiveUpdate.reload()
}
}
})
// Remove live update as the free plan is very limited (100 live updates per year). Do releases on Play Store instead.
// App.addListener("resume", async () => {
// const newChannelName = 'default'
// try {
// await LiveUpdate.setChannel({channel: newChannelName})
// console.log(`Device channel set to: ${newChannelName}`)
// } catch (error) {
// console.error('Failed to set channel', error)
// }
// const {nextBundleId} = await LiveUpdate.sync()
// if (nextBundleId) {
// // Ask the user if they want to apply the update immediately
// const shouldReload = confirm("A new update is available. Would you like to install it?")
// if (shouldReload) {
// await LiveUpdate.reload()
// }
// }
// })
}
@@ -93,7 +93,7 @@ function MyApp(props: AppProps<PageProps>) {
useHasLoaded()
const router = useRouter()
const [locale, setLocaleState] = useState(getLocale());
const [locale, setLocaleState] = useState(getLocale())
const setLocale = (newLocale: string) => {
document.cookie = `lang=${newLocale}; path=/; max-age=31536000`
setLocaleState(newLocale)