mirror of
https://github.com/NoCrypt/migu.git
synced 2026-04-19 07:32:05 +00:00
feat(android): auto updater
This commit is contained in:
parent
2ff58ca5bb
commit
ce5f6c88c3
15 changed files with 6269 additions and 1445 deletions
|
|
@ -37,10 +37,35 @@ android {
|
|||
abi {
|
||||
enable gradle.startParameter.taskNames.any { it.contains("Release") } // https://stackoverflow.com/a/39950584
|
||||
reset()
|
||||
include "armeabi-v7a", "arm64-v8a", "x86_64"
|
||||
include "arm64-v8a", "armeabi-v7a", "x86_64"
|
||||
universalApk true
|
||||
}
|
||||
}
|
||||
|
||||
// Map for the version code
|
||||
project.ext.versionCodes = ['arm64-v8a': 1, 'armeabi-v7a': 2, 'x86_64': 3, 'universal': 4, 'debug': 5]
|
||||
|
||||
android.applicationVariants.all { variant ->
|
||||
// Assign different version code for each output
|
||||
variant.outputs.each { output ->
|
||||
def versionCodes = project.ext.versionCodes
|
||||
def baseVersionCode = android.defaultConfig.versionCode
|
||||
def abiVersionCode = 0
|
||||
|
||||
if (output.getFilter(com.android.build.OutputFile.ABI)) {
|
||||
abiVersionCode = versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0)
|
||||
} else {
|
||||
// This is for the universal APK
|
||||
abiVersionCode = versionCodes.get('universal', 0)
|
||||
}
|
||||
|
||||
if (gradle.startParameter.taskNames.any { it.contains("Release") }) {
|
||||
output.versionCodeOverride = abiVersionCode * 1000000 + baseVersionCode
|
||||
} else {
|
||||
output.versionCodeOverride = versionCodes.get('debug') * 1000000 + baseVersionCode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
|
|
|||
|
|
@ -9,8 +9,10 @@ android {
|
|||
|
||||
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
||||
dependencies {
|
||||
implementation project(':capacitor-community-file-opener')
|
||||
implementation project(':capacitor-app')
|
||||
implementation project(':capacitor-browser')
|
||||
implementation project(':capacitor-filesystem')
|
||||
implementation project(':capacitor-local-notifications')
|
||||
implementation project(':capacitor-status-bar')
|
||||
implementation project(':capacitor-nodejs')
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@
|
|||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<uses-feature android:name="android.software.leanback" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
|
||||
</manifest>
|
||||
|
|
|
|||
|
|
@ -27,4 +27,5 @@ public class MainActivity extends BridgeActivity {
|
|||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,12 +2,18 @@
|
|||
include ':capacitor-android'
|
||||
project(':capacitor-android').projectDir = new File('../../node_modules/@capacitor/android/capacitor')
|
||||
|
||||
include ':capacitor-community-file-opener'
|
||||
project(':capacitor-community-file-opener').projectDir = new File('../../node_modules/@capacitor-community/file-opener/android')
|
||||
|
||||
include ':capacitor-app'
|
||||
project(':capacitor-app').projectDir = new File('../../node_modules/@capacitor/app/android')
|
||||
|
||||
include ':capacitor-browser'
|
||||
project(':capacitor-browser').projectDir = new File('../../node_modules/@capacitor/browser/android')
|
||||
|
||||
include ':capacitor-filesystem'
|
||||
project(':capacitor-filesystem').projectDir = new File('../../node_modules/@capacitor/filesystem/android')
|
||||
|
||||
include ':capacitor-local-notifications'
|
||||
project(':capacitor-local-notifications').projectDir = new File('../../node_modules/@capacitor/local-notifications/android')
|
||||
|
||||
|
|
|
|||
|
|
@ -27,10 +27,12 @@
|
|||
"webpack-merge": "^5.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@capacitor-community/file-opener": "^6.0.0",
|
||||
"@capacitor/android": "^6.1.1",
|
||||
"@capacitor/app": "^6.0.0",
|
||||
"@capacitor/browser": "^6.0.1",
|
||||
"@capacitor/core": "^6.1.1",
|
||||
"@capacitor/filesystem": "^6.0.0",
|
||||
"@capacitor/ios": "^6.1.1",
|
||||
"@capacitor/local-notifications": "^6.0.0",
|
||||
"@capacitor/status-bar": "^6.0.0",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { App } from '@capacitor/app'
|
||||
import { NodeJS } from 'capacitor-nodejs'
|
||||
import EventEmitter from 'events'
|
||||
import { AutoUpdater } from './update'
|
||||
|
||||
const ready = NodeJS.whenReady()
|
||||
|
||||
|
|
@ -33,3 +34,15 @@ main.once('version', async () => {
|
|||
const { version } = await App.getInfo()
|
||||
main.emit('version', version)
|
||||
})
|
||||
|
||||
const updater = new AutoUpdater('https://api.github.com/repos/NoCrypt/migu/releases/latest');
|
||||
main.on('update', async () => {
|
||||
console.log('[Android Updater] Checking for update...')
|
||||
await updater.initialize()
|
||||
// await updater.performUpdate();
|
||||
if (await updater.checkForUpdate()) main.emit('android-update-available')
|
||||
})
|
||||
|
||||
main.on('android-install-update', async () => {
|
||||
await updater.performUpdate();
|
||||
})
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
export const SUPPORTS = {
|
||||
offscreenRender: false,
|
||||
update: false,
|
||||
update: true,
|
||||
angle: false,
|
||||
doh: false,
|
||||
dht: true,
|
||||
|
|
|
|||
120
capacitor/src/update.js
Normal file
120
capacitor/src/update.js
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
import { App } from '@capacitor/app';
|
||||
import { Filesystem, Directory } from '@capacitor/filesystem';
|
||||
import { FileOpener } from '@capacitor-community/file-opener';
|
||||
|
||||
export class AutoUpdater {
|
||||
constructor(githubApiUrl) {
|
||||
this.githubApiUrl = githubApiUrl;
|
||||
this.currentVersion = null;
|
||||
this.appInfo = null;
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
const info = await App.getInfo();
|
||||
this.appInfo = info;
|
||||
this.currentVersion = info.version;
|
||||
this.cpuArchitecture = await this.getCPUArchitecture();
|
||||
}
|
||||
|
||||
async removeCachedAPKs(){
|
||||
const list = await Filesystem.readdir({path: './', directory: Directory.Cache})
|
||||
for (const file of list.files) {
|
||||
if (file.name.endsWith('.apk')) {
|
||||
await Filesystem.deleteFile({path: file.name, directory: Directory.Cache})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async getCPUArchitecture() {
|
||||
const versionMap = {'arm64-v8a': 1, 'armeabi-v7a': 2, 'x86_64': 3, 'universal': 4}; //5: debug
|
||||
const {build} = this.appInfo;
|
||||
|
||||
if (build.length === 7) {
|
||||
const architectureCode = parseInt(build.substring(0, 1));
|
||||
console.log(architectureCode)
|
||||
|
||||
if (architectureCode < 5) {
|
||||
for (const [arch, code] of Object.entries(versionMap)) {
|
||||
if (code === architectureCode) {
|
||||
return arch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If version code doesn't match expected format or no match found
|
||||
return 'universal';
|
||||
}
|
||||
|
||||
async checkForUpdate() {
|
||||
try {
|
||||
const response = await fetch(this.githubApiUrl);
|
||||
const releaseInfo = await response.json();
|
||||
|
||||
const latestVersion = releaseInfo.tag_name.replace('v', '');
|
||||
return this.isNewerVersion(latestVersion, this.currentVersion);
|
||||
// return true
|
||||
} catch (error) {
|
||||
console.error('Error checking for update:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
isNewerVersion(latestVersion, currentVersion) {
|
||||
const latest = latestVersion.split('.').map(Number);
|
||||
const current = currentVersion.split('.').map(Number);
|
||||
|
||||
for (let i = 0; i < latest.length; i++) {
|
||||
if (latest[i] > current[i]) return true;
|
||||
if (latest[i] < current[i]) return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async downloadUpdate() {
|
||||
await this.removeCachedAPKs();
|
||||
try {
|
||||
const response = await fetch(this.githubApiUrl);
|
||||
const releaseInfo = await response.json();
|
||||
|
||||
const assetName = `android-Migu-${releaseInfo.tag_name}-${this.cpuArchitecture}.apk`;
|
||||
const asset = releaseInfo.assets.find(a => a.name === assetName);
|
||||
|
||||
if (!asset) {
|
||||
console.error('Update file not found', assetName);
|
||||
return null;
|
||||
}
|
||||
|
||||
const fileName = `update-${releaseInfo.tag_name}.apk`;
|
||||
const result = await Filesystem.downloadFile({
|
||||
url: asset.browser_download_url,
|
||||
path: fileName,
|
||||
directory: Directory.Cache,
|
||||
});
|
||||
|
||||
return result.path;
|
||||
} catch (error) {
|
||||
console.error('Error downloading update:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async installUpdate(filePath) {
|
||||
try {
|
||||
await FileOpener.open({
|
||||
filePath,
|
||||
contentType: 'application/vnd.android.package-archive'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error installing update:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async performUpdate() {
|
||||
const filePath = await this.downloadUpdate();
|
||||
if (filePath) {
|
||||
await this.installUpdate(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
import { Toaster } from 'svelte-sonner'
|
||||
import Logout from './components/Logout.svelte'
|
||||
import Navbar from './components/Navbar.svelte'
|
||||
import { SUPPORTS } from '@/modules/support.js';
|
||||
|
||||
setContext('view', view)
|
||||
</script>
|
||||
|
|
@ -37,7 +38,7 @@
|
|||
<div class='overflow-hidden content-wrapper h-full z-10'>
|
||||
<Toaster visibleToasts={6} position='top-right' theme='dark' richColors duration={10000} closeButton toastOptions={{
|
||||
classes: {
|
||||
closeButton: "toast-close-button"
|
||||
closeButton: SUPPORTS.isAndroid ? "toast-close-button" : ""
|
||||
}
|
||||
|
||||
}} style="margin-top: var(--safe-area-top)"/>
|
||||
|
|
@ -50,12 +51,20 @@
|
|||
<style>
|
||||
|
||||
:global(.toast-close-button){
|
||||
bottom: 10px !important;
|
||||
right: 10px !important;
|
||||
bottom: -10px !important;
|
||||
right: -10px !important;
|
||||
left: unset !important;
|
||||
top: unset !important;
|
||||
}
|
||||
|
||||
:global(:where([data-sonner-toast]) :where([data-disabled='true']) ){
|
||||
opacity: 0 !important;
|
||||
}
|
||||
|
||||
:global(:root){
|
||||
--normal-bg: var(--dark-color-light) !important;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
will-change: width;
|
||||
top: 0 !important;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
<script>
|
||||
import Home from './views/Home/Home.svelte'
|
||||
import MediaHandler, { media } from './views/Player/MediaHandler.svelte'
|
||||
import Settings from '@/views/Settings/Settings.svelte'
|
||||
import Settings, { version } from '@/views/Settings/Settings.svelte'
|
||||
import WatchTogether from './views/WatchTogether/WatchTogether.svelte'
|
||||
import Miniplayer from 'svelte-miniplayer'
|
||||
import Search from './views/Search.svelte'
|
||||
|
|
@ -33,9 +33,43 @@
|
|||
$: maxwidth = $isMobile ? '200px' : '60rem'
|
||||
|
||||
onMount(() => {
|
||||
// Check update (ask if on Android, install if on PC)
|
||||
if($settings.enableAutoUpdate && SUPPORTS.update) IPC.emit('update')
|
||||
|
||||
if (SUPPORTS.isAndroid) {
|
||||
// Auto updater for android
|
||||
IPC.on('android-update-available', () => {
|
||||
toast.info('Update found', {
|
||||
description: 'Wanna install it?',
|
||||
action: {
|
||||
label: 'Install now',
|
||||
onClick: () => {
|
||||
console.log(version)
|
||||
IPC.emit('android-install-update')
|
||||
toast.loading('Downloading...', {
|
||||
description: 'Please allow the permission when asked. ',
|
||||
duration: Number.POSITIVE_INFINITY,
|
||||
dismissable: false,
|
||||
cancel:{
|
||||
label: 'Hide',
|
||||
onClick: () => {
|
||||
toast.dismiss()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
cancel: {
|
||||
label: 'Never show again',
|
||||
onClick: () => {
|
||||
$settings.enableAutoUpdate = false
|
||||
toast('Auto update disabled. You can re-enable it in Settings > App')
|
||||
}
|
||||
},
|
||||
duration: Number.POSITIVE_INFINITY
|
||||
})
|
||||
})
|
||||
|
||||
// Back button support
|
||||
let backButtonPressTimeout;
|
||||
window.Capacitor.Plugins.App.addListener("backButton", () => {
|
||||
if (page === "home" && $view === null && $rss === null) {
|
||||
|
|
|
|||
|
|
@ -62,8 +62,8 @@ a[href]:active, button:not([disabled]):active, fieldset:not([disabled]):active,
|
|||
}
|
||||
|
||||
[data-sonner-toaster][data-theme='dark'] {
|
||||
--normal-bg: var(--dark-color) !important;
|
||||
--normal-border: none !important;
|
||||
--normal-bg: var(--dark-color-light) !important;
|
||||
--normal-border: rgba(128, 128, 128, 0.297) !important;
|
||||
--normal-text: var(--dm-base-text-color) !important;
|
||||
|
||||
/* --success-bg: var(--success-color) !important; */
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ export const defaults = {
|
|||
slowSeeding: true,
|
||||
disableStartupVideo: true,
|
||||
amoledTheme: true,
|
||||
enableAutoUpdate: true,
|
||||
enableAutoUpdate: !SUPPORTS.isAndroid,
|
||||
torrentPersist: false,
|
||||
torrentDHT: false,
|
||||
torrentPeX: false,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
sunos: 'SunOS',
|
||||
win32: 'Windows'
|
||||
}
|
||||
let version = '1.0.0'
|
||||
export let version = '1.0.0'
|
||||
IPC.on('version', data => (version = data))
|
||||
IPC.emit('version')
|
||||
|
||||
|
|
|
|||
7477
pnpm-lock.yaml
7477
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue