feat: Android, opt, check update on startup (#10165)
* feat: Android, opt, check update on startup Signed-off-by: fufesou <linlong1266@gmail.com> * refact: check update only on startup Signed-off-by: fufesou <linlong1266@gmail.com> * fix: Android, "Download new version" Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
parent
3d17bf4990
commit
a23822074e
@ -15,6 +15,13 @@
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
|
||||
<queries>
|
||||
<intent>
|
||||
<!-- https://developer.android.com/training/package-visibility/use-cases#open-urls-custom-tabs -->
|
||||
<action android:name="android.support.customtabs.action.CustomTabsService" />
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
<application
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="RustDesk"
|
||||
|
@ -3633,3 +3633,20 @@ List<SubWindowResizeEdge>? get subWindowManagerEnableResizeEdges => isWindows
|
||||
void earlyAssert() {
|
||||
assert('\1' == '1');
|
||||
}
|
||||
|
||||
void checkUpdate() {
|
||||
if (isDesktop || isAndroid) {
|
||||
if (!bind.isCustomClient()) {
|
||||
platformFFI.registerEventHandler(
|
||||
kCheckSoftwareUpdateFinish, kCheckSoftwareUpdateFinish,
|
||||
(Map<String, dynamic> evt) async {
|
||||
if (evt['url'] is String) {
|
||||
stateGlobal.updateUrl.value = evt['url'];
|
||||
}
|
||||
});
|
||||
Timer(const Duration(seconds: 1), () async {
|
||||
bind.mainGetSoftwareUpdateUrl();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import 'package:flutter_hbb/desktop/pages/desktop_setting_page.dart';
|
||||
import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart';
|
||||
import 'package:flutter_hbb/models/platform_model.dart';
|
||||
import 'package:flutter_hbb/models/server_model.dart';
|
||||
import 'package:flutter_hbb/models/state_model.dart';
|
||||
import 'package:flutter_hbb/plugin/ui_manager.dart';
|
||||
import 'package:flutter_hbb/utils/multi_window_manager.dart';
|
||||
import 'package:get/get.dart';
|
||||
@ -39,7 +40,6 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
var updateUrl = '';
|
||||
var systemError = '';
|
||||
StreamSubscription? _uniLinksSubscription;
|
||||
var svcStopped = false.obs;
|
||||
@ -86,7 +86,8 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
if (!isOutgoingOnly) buildIDBoard(context),
|
||||
if (!isOutgoingOnly) buildPasswordBoard(context),
|
||||
FutureBuilder<Widget>(
|
||||
future: buildHelpCards(),
|
||||
future: Future.value(
|
||||
Obx(() => buildHelpCards(stateGlobal.updateUrl.value))),
|
||||
builder: (_, data) {
|
||||
if (data.hasData) {
|
||||
if (isIncomingOnly) {
|
||||
@ -415,7 +416,7 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
);
|
||||
}
|
||||
|
||||
Future<Widget> buildHelpCards() async {
|
||||
Widget buildHelpCards(String updateUrl) {
|
||||
if (!bind.isCustomClient() &&
|
||||
updateUrl.isNotEmpty &&
|
||||
!isCardClosed &&
|
||||
@ -669,20 +670,6 @@ class _DesktopHomePageState extends State<DesktopHomePage>
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (!bind.isCustomClient()) {
|
||||
platformFFI.registerEventHandler(
|
||||
kCheckSoftwareUpdateFinish, kCheckSoftwareUpdateFinish,
|
||||
(Map<String, dynamic> evt) async {
|
||||
if (evt['url'] is String) {
|
||||
setState(() {
|
||||
updateUrl = evt['url'];
|
||||
});
|
||||
}
|
||||
});
|
||||
Timer(const Duration(seconds: 1), () async {
|
||||
bind.mainGetSoftwareUpdateUrl();
|
||||
});
|
||||
}
|
||||
_updateTimer = periodic_immediate(const Duration(seconds: 1), () async {
|
||||
await gFFI.serverModel.fetchID();
|
||||
final error = await bind.mainGetError();
|
||||
|
@ -14,6 +14,7 @@ import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart';
|
||||
import 'package:flutter_hbb/mobile/widgets/dialog.dart';
|
||||
import 'package:flutter_hbb/models/platform_model.dart';
|
||||
import 'package:flutter_hbb/models/server_model.dart';
|
||||
import 'package:flutter_hbb/models/state_model.dart';
|
||||
import 'package:flutter_hbb/plugin/manager.dart';
|
||||
import 'package:flutter_hbb/plugin/widgets/desktop_settings.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
@ -120,6 +120,7 @@ Future<void> initEnv(String appType) async {
|
||||
void runMainApp(bool startService) async {
|
||||
// register uni links
|
||||
await initEnv(kAppTypeMain);
|
||||
checkUpdate();
|
||||
// trigger connection status updater
|
||||
await bind.mainCheckConnectStatus();
|
||||
if (startService) {
|
||||
@ -156,6 +157,7 @@ void runMainApp(bool startService) async {
|
||||
|
||||
void runMobileApp() async {
|
||||
await initEnv(kAppTypeMain);
|
||||
checkUpdate();
|
||||
if (isAndroid) androidChannelInit();
|
||||
if (isAndroid) platformFFI.syncAndroidServiceAppDirConfigPath();
|
||||
draggablePositions.load();
|
||||
|
@ -4,6 +4,7 @@ import 'package:auto_size_text_field/auto_size_text_field.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hbb/common/formatter/id_formatter.dart';
|
||||
import 'package:flutter_hbb/common/widgets/connection_page_title.dart';
|
||||
import 'package:flutter_hbb/models/state_model.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
@ -40,8 +41,6 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
||||
final _idController = IDTextEditingController();
|
||||
final RxBool _idEmpty = true.obs;
|
||||
|
||||
/// Update url. If it's not null, means an update is available.
|
||||
var _updateUrl = '';
|
||||
List<Peer> peers = [];
|
||||
|
||||
bool isPeersLoading = false;
|
||||
@ -72,22 +71,6 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
||||
}
|
||||
});
|
||||
}
|
||||
if (isAndroid) {
|
||||
if (!bind.isCustomClient()) {
|
||||
platformFFI.registerEventHandler(
|
||||
kCheckSoftwareUpdateFinish, kCheckSoftwareUpdateFinish,
|
||||
(Map<String, dynamic> evt) async {
|
||||
if (evt['url'] is String) {
|
||||
setState(() {
|
||||
_updateUrl = evt['url'];
|
||||
});
|
||||
}
|
||||
});
|
||||
Timer(const Duration(seconds: 1), () async {
|
||||
bind.mainGetSoftwareUpdateUrl();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@ -97,7 +80,8 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
||||
slivers: [
|
||||
SliverList(
|
||||
delegate: SliverChildListDelegate([
|
||||
if (!bind.isCustomClient()) _buildUpdateUI(),
|
||||
if (!bind.isCustomClient())
|
||||
Obx(() => _buildUpdateUI(stateGlobal.updateUrl.value)),
|
||||
_buildRemoteIDTextField(),
|
||||
])),
|
||||
SliverFillRemaining(
|
||||
@ -116,13 +100,21 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
||||
}
|
||||
|
||||
/// UI for software update.
|
||||
/// If [_updateUrl] is not empty, shows a button to update the software.
|
||||
Widget _buildUpdateUI() {
|
||||
return _updateUrl.isEmpty
|
||||
/// If _updateUrl] is not empty, shows a button to update the software.
|
||||
Widget _buildUpdateUI(String updateUrl) {
|
||||
return updateUrl.isEmpty
|
||||
? const SizedBox(height: 0)
|
||||
: InkWell(
|
||||
onTap: () async {
|
||||
final url = 'https://rustdesk.com/download';
|
||||
// https://pub.dev/packages/url_launcher#configuration
|
||||
// https://developer.android.com/training/package-visibility/use-cases#open-urls-custom-tabs
|
||||
//
|
||||
// `await launchUrl(Uri.parse(url))` can also run if skip
|
||||
// 1. The following check
|
||||
// 2. `<action android:name="android.support.customtabs.action.CustomTabsService" />` in AndroidManifest.xml
|
||||
//
|
||||
// But it is better to add the check.
|
||||
if (await canLaunchUrl(Uri.parse(url))) {
|
||||
await launchUrl(Uri.parse(url));
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import 'dart:typed_data';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hbb/common/widgets/setting_widgets.dart';
|
||||
import 'package:flutter_hbb/desktop/pages/desktop_setting_page.dart';
|
||||
import 'package:flutter_hbb/models/state_model.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:settings_ui/settings_ui.dart';
|
||||
@ -70,6 +71,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
||||
false; //androidVersion >= 26; // remove because not work on every device
|
||||
var _ignoreBatteryOpt = false;
|
||||
var _enableStartOnBoot = false;
|
||||
var _checkUpdateOnStartup = false;
|
||||
var _floatingWindowDisabled = false;
|
||||
var _keepScreenOn = KeepScreenOn.duringControlled; // relay on floating window
|
||||
var _enableAbr = false;
|
||||
@ -154,6 +156,13 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
||||
_enableStartOnBoot = enableStartOnBoot;
|
||||
}
|
||||
|
||||
var checkUpdateOnStartup =
|
||||
mainGetLocalBoolOptionSync(kOptionEnableCheckUpdate);
|
||||
if (checkUpdateOnStartup != _checkUpdateOnStartup) {
|
||||
update = true;
|
||||
_checkUpdateOnStartup = checkUpdateOnStartup;
|
||||
}
|
||||
|
||||
var floatingWindowDisabled =
|
||||
bind.mainGetLocalOption(key: kOptionDisableFloatingWindow) == "Y" ||
|
||||
!await AndroidPermissionManager.check(kSystemAlertWindow);
|
||||
@ -552,6 +561,22 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
|
||||
gFFI.invokeMethod(AndroidChannel.kSetStartOnBootOpt, toValue);
|
||||
}));
|
||||
|
||||
if (!bind.isCustomClient()) {
|
||||
enhancementsTiles.add(
|
||||
SettingsTile.switchTile(
|
||||
initialValue: _checkUpdateOnStartup,
|
||||
title:
|
||||
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
Text(translate('Check for software update on startup')),
|
||||
]),
|
||||
onToggle: (bool toValue) async {
|
||||
await mainSetLocalBoolOption(kOptionEnableCheckUpdate, toValue);
|
||||
setState(() => _checkUpdateOnStartup = toValue);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
onFloatingWindowChanged(bool toValue) async {
|
||||
if (toValue) {
|
||||
if (!await AndroidPermissionManager.check(kSystemAlertWindow)) {
|
||||
|
@ -25,6 +25,8 @@ class StateGlobal {
|
||||
|
||||
final isPortrait = false.obs;
|
||||
|
||||
final updateUrl = ''.obs;
|
||||
|
||||
String _inputSource = '';
|
||||
|
||||
// Use for desktop -> remote toolbar -> resolution
|
||||
|
@ -1418,7 +1418,8 @@ pub fn main_get_last_remote_id() -> String {
|
||||
}
|
||||
|
||||
pub fn main_get_software_update_url() {
|
||||
if get_local_option("enable-check-update".to_string()) != "N" {
|
||||
let opt = get_local_option(config::keys::OPTION_ENABLE_CHECK_UPDATE.to_string());
|
||||
if config::option2bool(config::keys::OPTION_ENABLE_CHECK_UPDATE, &opt) {
|
||||
crate::common::check_software_update();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user