diff --git a/.github/workflows/flutter-build.yml b/.github/workflows/flutter-build.yml
index 7ea06ba8e..ae7db7135 100644
--- a/.github/workflows/flutter-build.yml
+++ b/.github/workflows/flutter-build.yml
@@ -370,6 +370,92 @@ jobs:
generate-bridge-linux:
uses: ./.github/workflows/bridge.yml
+ build-rustdesk-ios:
+ needs: [generate-bridge-linux]
+ name: build rustdesk ios ipa ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-features }}]
+ runs-on: ${{ matrix.job.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ job:
+ - {
+ arch: aarch64,
+ target: aarch64-apple-ios,
+ os: macos-latest,
+ extra-build-features: "",
+ }
+ steps:
+ - name: Install dependencies
+ run: |
+ brew install nasm yasm
+ - name: Checkout source code
+ uses: actions/checkout@v3
+ - name: Install flutter
+ uses: subosito/flutter-action@v2
+ with:
+ channel: "stable"
+ flutter-version: ${{ env.FLUTTER_VERSION }}
+
+ - name: Clone deps
+ shell: bash
+ run: |
+ pushd /opt
+ sudo git clone https://github.com/Kingtous/rustdesk_thirdparty_lib.git --depth=1
+
+ - name: Restore bridge files
+ uses: actions/download-artifact@master
+ with:
+ name: bridge-artifact
+ path: ./
+
+ - name: Install Rust toolchain
+ uses: actions-rs/toolchain@v1
+ with:
+ toolchain: stable
+ target: ${{ matrix.job.target }}
+ override: true
+ profile: minimal # minimal component installation (ie, no documentation)
+
+ - uses: Swatinem/rust-cache@v2
+ with:
+ prefix-key: rustdesk-lib-cache
+ key: ${{ matrix.job.target }}-${{ matrix.job.extra-build-features }}
+
+ - name: Disable rust bridge build
+ shell: bash
+ run: |
+ sed -i build.rs.bak "s/gen_flutter_rust_bridge();/\/\//g" build.rs
+
+ - name: Build rustdesk lib
+ env:
+ VCPKG_ROOT: /opt/rustdesk_thirdparty_lib/vcpkg
+ run: |
+ rustup target add ${{ matrix.job.target }}
+ cargo build --features flutter --release --target aarch64-apple-ios --lib
+
+ - name: Build rustdesk
+ shell: bash
+ run: |
+ pushd flutter
+ flutter build ios --release
+
+ # - name: Upload Artifacts
+ # # if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
+ # uses: actions/upload-artifact@master
+ # with:
+ # name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.apk
+ # path: flutter/build/ios/ipa/*.ipa
+
+ # - name: Publish ipa package
+ # # if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
+ # uses: softprops/action-gh-release@v1
+ # with:
+ # prerelease: true
+ # tag_name: ${{ env.TAG_NAME }}
+ # files: |
+ # flutter/build/ios/ipa/*.ipa
+
+
build-rustdesk-android:
needs: [generate-bridge-linux]
name: build rustdesk android apk ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-features }}]
diff --git a/build.rs b/build.rs
index 85f21e7d0..7ff8f9ef6 100644
--- a/build.rs
+++ b/build.rs
@@ -123,9 +123,11 @@ fn main() {
build_manifest();
#[cfg(windows)]
build_windows();
- #[cfg(target_os = "macos")]
- build_mac();
- #[cfg(target_os = "macos")]
- println!("cargo:rustc-link-lib=framework=ApplicationServices");
+ let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
+ if target_os == "macos" {
+ #[cfg(target_os = "macos")]
+ build_mac();
+ println!("cargo:rustc-link-lib=framework=ApplicationServices");
+ }
println!("cargo:rerun-if-changed=build.rs");
}
diff --git a/examples/custom_plugin/Cargo.toml b/examples/custom_plugin/Cargo.toml
index 106e48ebb..b9ee06ae7 100644
--- a/examples/custom_plugin/Cargo.toml
+++ b/examples/custom_plugin/Cargo.toml
@@ -10,9 +10,14 @@ name = "custom_plugin"
path = "src/lib.rs"
crate-type = ["cdylib"]
+
+[features]
+default = ["flutter"]
+flutter = []
+
[dependencies]
lazy_static = "1.4.0"
-rustdesk = { path = "../../", version = "1.2.0"}
+rustdesk = { path = "../../", version = "1.2.0", features = ["flutter"]}
[profile.release]
lto = true
diff --git a/examples/custom_plugin/src/lib.rs b/examples/custom_plugin/src/lib.rs
index be051c1d9..0b21f3fc8 100644
--- a/examples/custom_plugin/src/lib.rs
+++ b/examples/custom_plugin/src/lib.rs
@@ -1,4 +1,4 @@
-use librustdesk::{api::RustDeskApiTable};
+use librustdesk::api::RustDeskApiTable;
/// This file demonstrates how to write a custom plugin for RustDesk.
use std::ffi::{c_char, c_int, CString};
diff --git a/flutter/ios/Flutter/AppFrameworkInfo.plist b/flutter/ios/Flutter/AppFrameworkInfo.plist
index 8d4492f97..9625e105d 100644
--- a/flutter/ios/Flutter/AppFrameworkInfo.plist
+++ b/flutter/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 9.0
+ 11.0
diff --git a/flutter/ios/Podfile b/flutter/ios/Podfile
index 0df0a09f8..3f67abf6a 100644
--- a/flutter/ios/Podfile
+++ b/flutter/ios/Podfile
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
-# platform :ios, '9.0'
+# platform :ios, '11.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
diff --git a/flutter/ios/Podfile.lock b/flutter/ios/Podfile.lock
index ff8c9282f..76d0bac73 100644
--- a/flutter/ios/Podfile.lock
+++ b/flutter/ios/Podfile.lock
@@ -1,194 +1,146 @@
PODS:
- - device_info (0.0.1):
+ - device_info_plus (0.0.1):
- Flutter
- - Firebase/Analytics (8.15.0):
- - Firebase/Core
- - Firebase/Core (8.15.0):
- - Firebase/CoreOnly
- - FirebaseAnalytics (~> 8.15.0)
- - Firebase/CoreOnly (8.15.0):
- - FirebaseCore (= 8.15.0)
- - firebase_analytics (9.1.8):
- - Firebase/Analytics (= 8.15.0)
- - firebase_core
+ - DKImagePickerController/Core (4.3.4):
+ - DKImagePickerController/ImageDataManager
+ - DKImagePickerController/Resource
+ - DKImagePickerController/ImageDataManager (4.3.4)
+ - DKImagePickerController/PhotoGallery (4.3.4):
+ - DKImagePickerController/Core
+ - DKPhotoGallery
+ - DKImagePickerController/Resource (4.3.4)
+ - DKPhotoGallery (0.0.17):
+ - DKPhotoGallery/Core (= 0.0.17)
+ - DKPhotoGallery/Model (= 0.0.17)
+ - DKPhotoGallery/Preview (= 0.0.17)
+ - DKPhotoGallery/Resource (= 0.0.17)
+ - SDWebImage
+ - SwiftyGif
+ - DKPhotoGallery/Core (0.0.17):
+ - DKPhotoGallery/Model
+ - DKPhotoGallery/Preview
+ - SDWebImage
+ - SwiftyGif
+ - DKPhotoGallery/Model (0.0.17):
+ - SDWebImage
+ - SwiftyGif
+ - DKPhotoGallery/Preview (0.0.17):
+ - DKPhotoGallery/Model
+ - DKPhotoGallery/Resource
+ - SDWebImage
+ - SwiftyGif
+ - DKPhotoGallery/Resource (0.0.17):
+ - SDWebImage
+ - SwiftyGif
+ - file_picker (0.0.1):
+ - DKImagePickerController/PhotoGallery
- Flutter
- - firebase_core (1.17.0):
- - Firebase/CoreOnly (= 8.15.0)
- - Flutter
- - FirebaseAnalytics (8.15.0):
- - FirebaseAnalytics/AdIdSupport (= 8.15.0)
- - FirebaseCore (~> 8.0)
- - FirebaseInstallations (~> 8.0)
- - GoogleUtilities/AppDelegateSwizzler (~> 7.7)
- - GoogleUtilities/MethodSwizzler (~> 7.7)
- - GoogleUtilities/Network (~> 7.7)
- - "GoogleUtilities/NSData+zlib (~> 7.7)"
- - nanopb (~> 2.30908.0)
- - FirebaseAnalytics/AdIdSupport (8.15.0):
- - FirebaseCore (~> 8.0)
- - FirebaseInstallations (~> 8.0)
- - GoogleAppMeasurement (= 8.15.0)
- - GoogleUtilities/AppDelegateSwizzler (~> 7.7)
- - GoogleUtilities/MethodSwizzler (~> 7.7)
- - GoogleUtilities/Network (~> 7.7)
- - "GoogleUtilities/NSData+zlib (~> 7.7)"
- - nanopb (~> 2.30908.0)
- - FirebaseCore (8.15.0):
- - FirebaseCoreDiagnostics (~> 8.0)
- - GoogleUtilities/Environment (~> 7.7)
- - GoogleUtilities/Logger (~> 7.7)
- - FirebaseCoreDiagnostics (8.15.0):
- - GoogleDataTransport (~> 9.1)
- - GoogleUtilities/Environment (~> 7.7)
- - GoogleUtilities/Logger (~> 7.7)
- - nanopb (~> 2.30908.0)
- - FirebaseInstallations (8.15.0):
- - FirebaseCore (~> 8.0)
- - GoogleUtilities/Environment (~> 7.7)
- - GoogleUtilities/UserDefaults (~> 7.7)
- - PromisesObjC (< 3.0, >= 1.2)
- Flutter (1.0.0)
- - GoogleAppMeasurement (8.15.0):
- - GoogleAppMeasurement/AdIdSupport (= 8.15.0)
- - GoogleUtilities/AppDelegateSwizzler (~> 7.7)
- - GoogleUtilities/MethodSwizzler (~> 7.7)
- - GoogleUtilities/Network (~> 7.7)
- - "GoogleUtilities/NSData+zlib (~> 7.7)"
- - nanopb (~> 2.30908.0)
- - GoogleAppMeasurement/AdIdSupport (8.15.0):
- - GoogleAppMeasurement/WithoutAdIdSupport (= 8.15.0)
- - GoogleUtilities/AppDelegateSwizzler (~> 7.7)
- - GoogleUtilities/MethodSwizzler (~> 7.7)
- - GoogleUtilities/Network (~> 7.7)
- - "GoogleUtilities/NSData+zlib (~> 7.7)"
- - nanopb (~> 2.30908.0)
- - GoogleAppMeasurement/WithoutAdIdSupport (8.15.0):
- - GoogleUtilities/AppDelegateSwizzler (~> 7.7)
- - GoogleUtilities/MethodSwizzler (~> 7.7)
- - GoogleUtilities/Network (~> 7.7)
- - "GoogleUtilities/NSData+zlib (~> 7.7)"
- - nanopb (~> 2.30908.0)
- - GoogleDataTransport (9.1.4):
- - GoogleUtilities/Environment (~> 7.7)
- - nanopb (< 2.30910.0, >= 2.30908.0)
- - PromisesObjC (< 3.0, >= 1.2)
- - GoogleUtilities/AppDelegateSwizzler (7.7.0):
- - GoogleUtilities/Environment
- - GoogleUtilities/Logger
- - GoogleUtilities/Network
- - GoogleUtilities/Environment (7.7.0):
- - PromisesObjC (< 3.0, >= 1.2)
- - GoogleUtilities/Logger (7.7.0):
- - GoogleUtilities/Environment
- - GoogleUtilities/MethodSwizzler (7.7.0):
- - GoogleUtilities/Logger
- - GoogleUtilities/Network (7.7.0):
- - GoogleUtilities/Logger
- - "GoogleUtilities/NSData+zlib"
- - GoogleUtilities/Reachability
- - "GoogleUtilities/NSData+zlib (7.7.0)"
- - GoogleUtilities/Reachability (7.7.0):
- - GoogleUtilities/Logger
- - GoogleUtilities/UserDefaults (7.7.0):
- - GoogleUtilities/Logger
+ - flutter_keyboard_visibility (0.0.1):
+ - Flutter
+ - FMDB (2.7.5):
+ - FMDB/standard (= 2.7.5)
+ - FMDB/standard (2.7.5)
- image_picker_ios (0.0.1):
- Flutter
- MTBBarcodeScanner (5.0.11)
- - nanopb (2.30908.0):
- - nanopb/decode (= 2.30908.0)
- - nanopb/encode (= 2.30908.0)
- - nanopb/decode (2.30908.0)
- - nanopb/encode (2.30908.0)
- - package_info (0.0.1):
+ - package_info_plus (0.4.5):
- Flutter
- - path_provider_ios (0.0.1):
+ - path_provider_foundation (0.0.1):
- Flutter
- - PromisesObjC (2.1.0)
+ - FlutterMacOS
- qr_code_scanner (0.2.0):
- Flutter
- MTBBarcodeScanner
- - shared_preferences_ios (0.0.1):
+ - SDWebImage (5.15.5):
+ - SDWebImage/Core (= 5.15.5)
+ - SDWebImage/Core (5.15.5)
+ - sqflite (0.0.2):
+ - Flutter
+ - FMDB (>= 2.7.5)
+ - SwiftyGif (5.4.4)
+ - uni_links (0.0.1):
- Flutter
- url_launcher_ios (0.0.1):
- Flutter
+ - video_player_avfoundation (0.0.1):
+ - Flutter
- wakelock (0.0.1):
- Flutter
DEPENDENCIES:
- - device_info (from `.symlinks/plugins/device_info/ios`)
- - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`)
- - firebase_core (from `.symlinks/plugins/firebase_core/ios`)
+ - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
+ - file_picker (from `.symlinks/plugins/file_picker/ios`)
- Flutter (from `Flutter`)
+ - flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- - package_info (from `.symlinks/plugins/package_info/ios`)
- - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
+ - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
+ - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`)
- qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`)
- - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
+ - sqflite (from `.symlinks/plugins/sqflite/ios`)
+ - uni_links (from `.symlinks/plugins/uni_links/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
+ - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`)
- wakelock (from `.symlinks/plugins/wakelock/ios`)
SPEC REPOS:
trunk:
- - Firebase
- - FirebaseAnalytics
- - FirebaseCore
- - FirebaseCoreDiagnostics
- - FirebaseInstallations
- - GoogleAppMeasurement
- - GoogleDataTransport
- - GoogleUtilities
+ - DKImagePickerController
+ - DKPhotoGallery
+ - FMDB
- MTBBarcodeScanner
- - nanopb
- - PromisesObjC
+ - SDWebImage
+ - SwiftyGif
EXTERNAL SOURCES:
- device_info:
- :path: ".symlinks/plugins/device_info/ios"
- firebase_analytics:
- :path: ".symlinks/plugins/firebase_analytics/ios"
- firebase_core:
- :path: ".symlinks/plugins/firebase_core/ios"
+ device_info_plus:
+ :path: ".symlinks/plugins/device_info_plus/ios"
+ file_picker:
+ :path: ".symlinks/plugins/file_picker/ios"
Flutter:
:path: Flutter
+ flutter_keyboard_visibility:
+ :path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
- package_info:
- :path: ".symlinks/plugins/package_info/ios"
- path_provider_ios:
- :path: ".symlinks/plugins/path_provider_ios/ios"
+ package_info_plus:
+ :path: ".symlinks/plugins/package_info_plus/ios"
+ path_provider_foundation:
+ :path: ".symlinks/plugins/path_provider_foundation/ios"
qr_code_scanner:
:path: ".symlinks/plugins/qr_code_scanner/ios"
- shared_preferences_ios:
- :path: ".symlinks/plugins/shared_preferences_ios/ios"
+ sqflite:
+ :path: ".symlinks/plugins/sqflite/ios"
+ uni_links:
+ :path: ".symlinks/plugins/uni_links/ios"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
+ video_player_avfoundation:
+ :path: ".symlinks/plugins/video_player_avfoundation/ios"
wakelock:
:path: ".symlinks/plugins/wakelock/ios"
SPEC CHECKSUMS:
- device_info: d7d233b645a32c40dfdc212de5cf646ca482f175
- Firebase: 5f8193dff4b5b7c5d5ef72ae54bb76c08e2b841d
- firebase_analytics: 92d27947c7516981cabdc0acbb33cd0687bcda44
- firebase_core: aa1b92020533f5c23955e388c347c58fd64f8627
- FirebaseAnalytics: 7761cbadb00a717d8d0939363eb46041526474fa
- FirebaseCore: 5743c5785c074a794d35f2fff7ecc254a91e08b1
- FirebaseCoreDiagnostics: 92e07a649aeb66352b319d43bdd2ee3942af84cb
- FirebaseInstallations: 40bd9054049b2eae9a2c38ef1c3dd213df3605cd
- Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
- GoogleAppMeasurement: 4c19f031220c72464d460c9daa1fb5d1acce958e
- GoogleDataTransport: 5fffe35792f8b96ec8d6775f5eccd83c998d5a3b
- GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1
+ device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed
+ DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
+ DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
+ file_picker: ce3938a0df3cc1ef404671531facef740d03f920
+ Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
+ flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
+ FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
image_picker_ios: b786a5dcf033a8336a657191401bfdf12017dabb
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
- nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
- package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
- path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
- PromisesObjC: 99b6f43f9e1044bd87a95a60beff28c2c44ddb72
+ package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
+ path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
- shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
- url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
+ SDWebImage: fd7e1a22f00303e058058278639bf6196ee431fe
+ sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
+ SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
+ uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
+ url_launcher_ios: ae1517e5e344f5544fb090b079e11f399dfbe4d2
+ video_player_avfoundation: e489aac24ef5cf7af82702979ed16f2a5ef84cff
wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f
-PODFILE CHECKSUM: a00077baecbb97321490c14848fceed3893ca92a
+PODFILE CHECKSUM: c649b4e69a3086d323110011d04604e416ad0dcd
-COCOAPODS: 1.11.3
+COCOAPODS: 1.12.0
diff --git a/flutter/ios/Runner.xcodeproj/project.pbxproj b/flutter/ios/Runner.xcodeproj/project.pbxproj
index 953dad47b..06ecbdd13 100644
--- a/flutter/ios/Runner.xcodeproj/project.pbxproj
+++ b/flutter/ios/Runner.xcodeproj/project.pbxproj
@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 51;
+ objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@@ -228,6 +228,7 @@
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@@ -264,6 +265,7 @@
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@@ -338,6 +340,7 @@
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGNING_ALLOWED = NO;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
@@ -351,7 +354,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -414,6 +417,7 @@
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGNING_ALLOWED = NO;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
@@ -433,7 +437,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -469,6 +473,7 @@
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGNING_ALLOWED = NO;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
@@ -482,7 +487,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
diff --git a/flutter/ios/Runner/AppDelegate.swift b/flutter/ios/Runner/AppDelegate.swift
index 203cfff11..38ac2d8cd 100644
--- a/flutter/ios/Runner/AppDelegate.swift
+++ b/flutter/ios/Runner/AppDelegate.swift
@@ -13,9 +13,9 @@ import Flutter
}
public func dummyMethodToEnforceBundling() {
- get_rgba();
- free_rgba(nil);
- get_by_name("", "");
- set_by_name("", "");
+// get_rgba();
+// free_rgba(nil);
+// get_by_name("", "");
+// set_by_name("", "");
}
}
diff --git a/flutter/ios/Runner/Info.plist b/flutter/ios/Runner/Info.plist
index 3886d2456..873fe3751 100644
--- a/flutter/ios/Runner/Info.plist
+++ b/flutter/ios/Runner/Info.plist
@@ -49,5 +49,9 @@
This app needs camera access to scan QR codes
NSPhotoLibraryUsageDescription
This app needs photo library access to get QR codes from image
+ CADisableMinimumFrameDurationOnPhone
+
+ UIApplicationSupportsIndirectInputEvents
+
diff --git a/flutter/ios/Runner/ffi.h b/flutter/ios/Runner/ffi.h
index 701ec4b09..755bf99fe 100644
--- a/flutter/ios/Runner/ffi.h
+++ b/flutter/ios/Runner/ffi.h
@@ -1,4 +1,4 @@
-void* get_rgba();
-void free_rgba(void*);
-void set_by_name(const char*, const char*);
-const char* get_by_name(const char*, const char*);
+//void* get_rgba();
+//void free_rgba(void*);
+//void set_by_name(const char*, const char*);
+//const char* get_by_name(const char*, const char*);
diff --git a/flutter/pubspec.lock b/flutter/pubspec.lock
index 639ee04de..1edf94527 100644
--- a/flutter/pubspec.lock
+++ b/flutter/pubspec.lock
@@ -1571,5 +1571,5 @@ packages:
source: hosted
version: "0.1.1"
sdks:
- dart: ">=2.18.0 <4.0.0"
+ dart: ">=2.18.0 <3.0.0"
flutter: ">=3.3.0"
diff --git a/libs/scrap/build.rs b/libs/scrap/build.rs
index 8939cd214..b0d800545 100644
--- a/libs/scrap/build.rs
+++ b/libs/scrap/build.rs
@@ -15,7 +15,7 @@ fn link_vcpkg(mut path: PathBuf, name: &str) -> PathBuf {
let mut target = if target_os == "macos" {
if target_arch == "x64" {
"x64-osx".to_owned()
- } else if target_arch == "arm64"{
+ } else if target_arch == "arm64" {
"arm64-osx".to_owned()
} else {
format!("{}-{}", target_arch, target_os)
diff --git a/libs/scrap/examples/capture_mag.rs b/libs/scrap/examples/capture_mag.rs
index 81b2d8573..047020899 100644
--- a/libs/scrap/examples/capture_mag.rs
+++ b/libs/scrap/examples/capture_mag.rs
@@ -3,9 +3,9 @@ extern crate scrap;
use std::fs::File;
+use scrap::{i420_to_rgb, Display};
#[cfg(windows)]
use scrap::{CapturerMag, TraitCapturer};
-use scrap::{i420_to_rgb, Display};
fn main() {
let n = Display::all().unwrap().len();
diff --git a/libs/scrap/examples/record-screen.rs b/libs/scrap/examples/record-screen.rs
index 5df97838e..10ad66e09 100644
--- a/libs/scrap/examples/record-screen.rs
+++ b/libs/scrap/examples/record-screen.rs
@@ -18,7 +18,7 @@ use webm::mux;
use webm::mux::Track;
use scrap::vpxcodec as vpx_encode;
-use scrap::{TraitCapturer, Capturer, Display, STRIDE_ALIGN};
+use scrap::{Capturer, Display, TraitCapturer, STRIDE_ALIGN};
const USAGE: &'static str = "
Simple WebM screen capture.
diff --git a/libs/scrap/src/common/mod.rs b/libs/scrap/src/common/mod.rs
index 26b946401..292f371c6 100644
--- a/libs/scrap/src/common/mod.rs
+++ b/libs/scrap/src/common/mod.rs
@@ -64,6 +64,9 @@ pub fn would_block_if_equal(old: &mut Vec, b: &[u8]) -> std::io::Result<()>
pub trait TraitCapturer {
fn set_use_yuv(&mut self, use_yuv: bool);
+
+ // We doesn't support
+ #[cfg(not(any(target_os = "ios")))]
fn frame<'a>(&'a mut self, timeout: std::time::Duration) -> std::io::Result>;
#[cfg(windows)]
diff --git a/libs/scrap/src/wayland.rs b/libs/scrap/src/wayland.rs
index 82b219306..a5c4a3903 100644
--- a/libs/scrap/src/wayland.rs
+++ b/libs/scrap/src/wayland.rs
@@ -1,3 +1,3 @@
+pub mod capturable;
pub mod pipewire;
mod pipewire_dbus;
-pub mod capturable;
diff --git a/src/api.rs b/src/api.rs
index 1c993a5ee..a0ea5df1c 100644
--- a/src/api.rs
+++ b/src/api.rs
@@ -1,32 +1,87 @@
-use std::ffi::c_char;
+use std::ffi::{c_char};
-use crate::plugins::PLUGIN_REGISTRAR;
+use crate::{
+ flutter::{FlutterHandler, SESSIONS},
+ plugins::PLUGIN_REGISTRAR,
+ ui_session_interface::Session,
+};
// API provided by RustDesk.
pub type LoadPluginFunc = fn(*const c_char) -> i32;
pub type UnloadPluginFunc = fn(*const c_char) -> i32;
+pub type AddSessionFunc = fn(session_id: String) -> bool;
+pub type RemoveSessionFunc = fn(session_id: &String) -> bool;
+pub type AddSessionHookFunc = fn(session_id: String, key: String, hook: SessionHook) -> bool;
+pub type RemoveSessionHookFunc = fn(session_id: String, key: &String) -> bool;
-#[repr(C)]
-pub struct RustDeskApiTable {
- pub(crate) register_plugin: LoadPluginFunc,
- pub(crate) unload_plugin: UnloadPluginFunc,
+/// Hooks for session.
+#[derive(Clone)]
+pub enum SessionHook {
+ OnSessionRgba(fn(String, Vec) -> Vec),
+}
+
+// #[repr(C)]
+pub struct RustDeskApiTable {
+ pub(crate) load_plugin: LoadPluginFunc,
+ pub(crate) unload_plugin: UnloadPluginFunc,
+ pub add_session: AddSessionFunc,
+ pub remove_session: RemoveSessionFunc,
+ pub add_session_hook: AddSessionHookFunc,
+ pub remove_session_hook: RemoveSessionHookFunc,
}
-#[no_mangle]
fn load_plugin(path: *const c_char) -> i32 {
PLUGIN_REGISTRAR.load_plugin(path)
}
-#[no_mangle]
fn unload_plugin(path: *const c_char) -> i32 {
PLUGIN_REGISTRAR.unload_plugin(path)
}
+fn add_session(session_id: String) -> bool {
+ // let mut sessions = SESSIONS.write().unwrap();
+ // if sessions.contains_key(&session.id) {
+ // return false;
+ // }
+ // let _ = sessions.insert(session.id.to_owned(), session);
+ // true
+ false
+}
+
+fn remove_session(session_id: &String) -> bool {
+ let mut sessions = SESSIONS.write().unwrap();
+ if !sessions.contains_key(session_id) {
+ return false;
+ }
+ let _ = sessions.remove(session_id);
+ true
+}
+
+fn add_session_hook(session_id: String, key: String, hook: SessionHook) -> bool {
+ let sessions = SESSIONS.read().unwrap();
+ if let Some(session) = sessions.get(&session_id) {
+ return session.add_session_hook(key, hook);
+ }
+ false
+}
+
+fn remove_session_hook(session_id: String, key: &String) -> bool {
+ let sessions = SESSIONS.read().unwrap();
+ if let Some(session) = sessions.get(&session_id) {
+ return session.remove_session_hook(key);
+ }
+ false
+}
+
impl Default for RustDeskApiTable {
fn default() -> Self {
Self {
- register_plugin: load_plugin,
- unload_plugin: unload_plugin,
+ load_plugin,
+ unload_plugin,
+ add_session,
+ remove_session,
+ add_session_hook,
+ remove_session_hook,
}
}
}
diff --git a/src/client.rs b/src/client.rs
index d889e86cd..1dd525984 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -55,7 +55,6 @@ use scrap::{
use crate::{
common::{self, is_keyboard_mode_supported},
- server::video_service::{SCRAP_X11_REF_URL, SCRAP_X11_REQUIRED},
};
#[cfg(not(any(target_os = "android", target_os = "ios")))]
@@ -74,6 +73,27 @@ pub const MILLI1: Duration = Duration::from_millis(1);
pub const SEC30: Duration = Duration::from_secs(30);
pub const VIDEO_QUEUE_SIZE: usize = 120;
+pub const LOGIN_MSG_DESKTOP_NOT_INITED: &str = "Desktop env is not inited";
+pub const LOGIN_MSG_DESKTOP_SESSION_NOT_READY: &str = "Desktop session not ready";
+pub const LOGIN_MSG_DESKTOP_XSESSION_FAILED: &str = "Desktop xsession failed";
+pub const LOGIN_MSG_DESKTOP_SESSION_ANOTHER_USER: &str = "Desktop session another user login";
+pub const LOGIN_MSG_DESKTOP_XORG_NOT_FOUND: &str = "Desktop xorg not found";
+// ls /usr/share/xsessions/
+pub const LOGIN_MSG_DESKTOP_NO_DESKTOP: &str = "Desktop none";
+pub const LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_EMPTY: &str =
+ "Desktop session not ready, password empty";
+pub const LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_WRONG: &str =
+ "Desktop session not ready, password wrong";
+pub const LOGIN_MSG_PASSWORD_EMPTY: &str = "Empty Password";
+pub const LOGIN_MSG_PASSWORD_WRONG: &str = "Wrong Password";
+pub const LOGIN_MSG_NO_PASSWORD_ACCESS: &str = "No Password Access";
+pub const LOGIN_MSG_OFFLINE: &str = "Offline";
+pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "Wayland requires Ubuntu 21.04 or higher version.";
+pub const SCRAP_OTHER_VERSION_OR_X11_REQUIRED: &str =
+ "Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.";
+pub const SCRAP_X11_REQUIRED: &str = "x11 expected";
+pub const SCRAP_X11_REF_URL: &str = "https://rustdesk.com/docs/en/manual/linux/#x11-required";
+
/// Client of the remote desktop.
pub struct Client;
@@ -1970,49 +1990,49 @@ struct LoginErrorMsgBox {
lazy_static::lazy_static! {
static ref LOGIN_ERROR_MAP: Arc> = {
use hbb_common::config::LINK_HEADLESS_LINUX_SUPPORT;
- let map = HashMap::from([(crate::server::LOGIN_MSG_DESKTOP_SESSION_NOT_READY, LoginErrorMsgBox{
+ let map = HashMap::from([(LOGIN_MSG_DESKTOP_SESSION_NOT_READY, LoginErrorMsgBox{
msgtype: "session-login",
title: "",
text: "",
link: "",
try_again: true,
- }), (crate::server::LOGIN_MSG_DESKTOP_XSESSION_FAILED, LoginErrorMsgBox{
+ }), (LOGIN_MSG_DESKTOP_XSESSION_FAILED, LoginErrorMsgBox{
msgtype: "session-re-login",
title: "",
text: "",
link: "",
try_again: true,
- }), (crate::server::LOGIN_MSG_DESKTOP_SESSION_ANOTHER_USER, LoginErrorMsgBox{
+ }), (LOGIN_MSG_DESKTOP_SESSION_ANOTHER_USER, LoginErrorMsgBox{
msgtype: "info-nocancel",
title: "another_user_login_title_tip",
text: "another_user_login_text_tip",
link: "",
try_again: false,
- }), (crate::server::LOGIN_MSG_DESKTOP_XORG_NOT_FOUND, LoginErrorMsgBox{
+ }), (LOGIN_MSG_DESKTOP_XORG_NOT_FOUND, LoginErrorMsgBox{
msgtype: "info-nocancel",
title: "xorg_not_found_title_tip",
text: "xorg_not_found_text_tip",
link: LINK_HEADLESS_LINUX_SUPPORT,
try_again: true,
- }), (crate::server::LOGIN_MSG_DESKTOP_NO_DESKTOP, LoginErrorMsgBox{
+ }), (LOGIN_MSG_DESKTOP_NO_DESKTOP, LoginErrorMsgBox{
msgtype: "info-nocancel",
title: "no_desktop_title_tip",
text: "no_desktop_text_tip",
link: LINK_HEADLESS_LINUX_SUPPORT,
try_again: true,
- }), (crate::server::LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_EMPTY, LoginErrorMsgBox{
+ }), (LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_EMPTY, LoginErrorMsgBox{
msgtype: "session-login-password",
title: "",
text: "",
link: "",
try_again: true,
- }), (crate::server::LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_WRONG, LoginErrorMsgBox{
+ }), (LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_WRONG, LoginErrorMsgBox{
msgtype: "session-login-re-password",
title: "",
text: "",
link: "",
try_again: true,
- }), (crate::server::LOGIN_MSG_NO_PASSWORD_ACCESS, LoginErrorMsgBox{
+ }), (LOGIN_MSG_NO_PASSWORD_ACCESS, LoginErrorMsgBox{
msgtype: "wait-remote-accept-nook",
title: "Prompt",
text: "Please wait for the remote side to accept your session request...",
@@ -2030,11 +2050,11 @@ pub fn handle_login_error(
err: &str,
interface: &impl Interface,
) -> bool {
- if err == crate::server::LOGIN_MSG_PASSWORD_EMPTY {
+ if err == LOGIN_MSG_PASSWORD_EMPTY {
lc.write().unwrap().password = Default::default();
interface.msgbox("input-password", "Password Required", "", "");
true
- } else if err == crate::server::LOGIN_MSG_PASSWORD_WRONG {
+ } else if err == LOGIN_MSG_PASSWORD_WRONG {
lc.write().unwrap().password = Default::default();
interface.msgbox("re-input-password", err, "Do you want to enter again?", "");
true
diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs
index 4cc7fd825..919347e5f 100644
--- a/src/client/io_loop.rs
+++ b/src/client/io_loop.rs
@@ -36,6 +36,7 @@ use crate::client::{
use crate::common::{self, update_clipboard};
use crate::common::{get_default_sound_input, set_sound_input};
use crate::ui_session_interface::{InvokeUiSession, Session};
+#[cfg(not(any(target_os = "ios")))]
use crate::{audio_service, ConnInner, CLIENT_SERVER};
use crate::{client::Data, client::Interface};
@@ -303,60 +304,65 @@ impl Remote {
if let Some(device) = default_sound_device {
set_sound_input(device);
}
- // Create a channel to receive error or closed message
- let (tx, rx) = std::sync::mpsc::channel();
- let (tx_audio_data, mut rx_audio_data) = hbb_common::tokio::sync::mpsc::unbounded_channel();
- // Create a stand-alone inner, add subscribe to audio service
- let conn_id = CLIENT_SERVER.write().unwrap().get_new_id();
- let client_conn_inner = ConnInner::new(conn_id.clone(), Some(tx_audio_data), None);
- // now we subscribe
- CLIENT_SERVER.write().unwrap().subscribe(
- audio_service::NAME,
- client_conn_inner.clone(),
- true,
- );
- let tx_audio = self.sender.clone();
- std::thread::spawn(move || {
- loop {
- // check if client is closed
- match rx.try_recv() {
- Ok(_) | Err(std::sync::mpsc::TryRecvError::Disconnected) => {
- log::debug!("Exit voice call audio service of client");
- // unsubscribe
- CLIENT_SERVER.write().unwrap().subscribe(
- audio_service::NAME,
- client_conn_inner,
- false,
- );
- break;
- }
- _ => {}
- }
- match rx_audio_data.try_recv() {
- Ok((_instant, msg)) => match &msg.union {
- Some(message::Union::AudioFrame(frame)) => {
- let mut msg = Message::new();
- msg.set_audio_frame(frame.clone());
- tx_audio.send(Data::Message(msg)).ok();
- }
- Some(message::Union::Misc(misc)) => {
- let mut msg = Message::new();
- msg.set_misc(misc.clone());
- tx_audio.send(Data::Message(msg)).ok();
+ // iOS does not have this server.
+ #[cfg(not(any(target_os = "ios")))]
+ {
+ // Create a channel to receive error or closed message
+ let (tx, rx) = std::sync::mpsc::channel();
+ let (tx_audio_data, mut rx_audio_data) = hbb_common::tokio::sync::mpsc::unbounded_channel();
+ // Create a stand-alone inner, add subscribe to audio service
+ let conn_id = CLIENT_SERVER.write().unwrap().get_new_id();
+ let client_conn_inner = ConnInner::new(conn_id.clone(), Some(tx_audio_data), None);
+ // now we subscribe
+ CLIENT_SERVER.write().unwrap().subscribe(
+ audio_service::NAME,
+ client_conn_inner.clone(),
+ true,
+ );
+ let tx_audio = self.sender.clone();
+ std::thread::spawn(move || {
+ loop {
+ // check if client is closed
+ match rx.try_recv() {
+ Ok(_) | Err(std::sync::mpsc::TryRecvError::Disconnected) => {
+ log::debug!("Exit voice call audio service of client");
+ // unsubscribe
+ CLIENT_SERVER.write().unwrap().subscribe(
+ audio_service::NAME,
+ client_conn_inner,
+ false,
+ );
+ break;
}
_ => {}
- },
- Err(err) => {
- if err == TryRecvError::Empty {
- // ignore
- } else {
- log::debug!("Failed to record local audio channel: {}", err);
+ }
+ match rx_audio_data.try_recv() {
+ Ok((_instant, msg)) => match &msg.union {
+ Some(message::Union::AudioFrame(frame)) => {
+ let mut msg = Message::new();
+ msg.set_audio_frame(frame.clone());
+ tx_audio.send(Data::Message(msg)).ok();
+ }
+ Some(message::Union::Misc(misc)) => {
+ let mut msg = Message::new();
+ msg.set_misc(misc.clone());
+ tx_audio.send(Data::Message(msg)).ok();
+ }
+ _ => {}
+ },
+ Err(err) => {
+ if err == TryRecvError::Empty {
+ // ignore
+ } else {
+ log::debug!("Failed to record local audio channel: {}", err);
+ }
}
}
}
- }
- });
- Some(tx)
+ });
+ return Some(tx);
+ }
+ None
}
async fn handle_msg_from_ui(&mut self, data: Data, peer: &mut Stream) -> bool {
diff --git a/src/common.rs b/src/common.rs
index 3cf10eaba..c96e42b37 100644
--- a/src/common.rs
+++ b/src/common.rs
@@ -782,6 +782,7 @@ pub fn make_fd_to_json(id: i32, path: String, entries: &Vec) -> Strin
/// 1. Try to send the url scheme from ipc.
/// 2. If failed to send the url scheme, we open a new main window to handle this url scheme.
pub fn handle_url_scheme(url: String) {
+ #[cfg(not(target_os = "ios"))]
if let Err(err) = crate::ipc::send_url_scheme(url.clone()) {
log::debug!("Send the url to the existing flutter process failed, {}. Let's open a new program to handle this.", err);
let _ = crate::run_me(vec![url]);
@@ -801,6 +802,9 @@ pub fn decode64>(input: T) -> Result, base64::DecodeError
}
pub async fn get_key(sync: bool) -> String {
+ #[cfg(target_os = "ios")]
+ let mut key = Config::get_option("key");
+ #[cfg(not(target_os = "ios"))]
let mut key = if sync {
Config::get_option("key")
} else {
diff --git a/src/flutter.rs b/src/flutter.rs
index 8c4522e47..34fe469fc 100644
--- a/src/flutter.rs
+++ b/src/flutter.rs
@@ -40,9 +40,9 @@ pub(super) const APP_TYPE_DESKTOP_FILE_TRANSFER: &str = "file transfer";
pub(super) const APP_TYPE_DESKTOP_PORT_FORWARD: &str = "port forward";
lazy_static::lazy_static! {
- pub static ref CUR_SESSION_ID: RwLock = Default::default();
- pub static ref SESSIONS: RwLock>> = Default::default();
- pub static ref GLOBAL_EVENT_STREAM: RwLock>> = Default::default(); // rust to dart event channel
+ pub(crate) static ref CUR_SESSION_ID: RwLock = Default::default();
+ pub(crate) static ref SESSIONS: RwLock>> = Default::default();
+ pub(crate) static ref GLOBAL_EVENT_STREAM: RwLock>> = Default::default(); // rust to dart event channel
}
#[cfg(all(target_os = "windows", feature = "flutter_texture_render"))]
@@ -146,6 +146,8 @@ pub struct FlutterHandler {
notify_rendered: Arc>,
renderer: Arc>,
peer_info: Arc>,
+ #[cfg(not(any(target_os = "android", target_os = "ios")))]
+ hooks: Arc>>,
}
#[cfg(not(feature = "flutter_texture_render"))]
@@ -157,6 +159,8 @@ pub struct FlutterHandler {
pub rgba: Arc>>,
pub rgba_valid: Arc,
peer_info: Arc>,
+ #[cfg(not(any(target_os = "android", target_os = "ios")))]
+ hooks: Arc>>,
}
#[cfg(feature = "flutter_texture_render")]
@@ -255,7 +259,7 @@ impl FlutterHandler {
}
}
- pub fn close_event_stream(&mut self) {
+ pub(crate) fn close_event_stream(&mut self) {
let mut stream_lock = self.event_stream.write().unwrap();
if let Some(stream) = &*stream_lock {
stream.add(EventToUI::Event("close".to_owned()));
@@ -277,6 +281,28 @@ impl FlutterHandler {
serde_json::ser::to_string(&msg_vec).unwrap_or("".to_owned())
}
+ #[cfg(not(any(target_os = "android", target_os = "ios")))]
+ pub(crate) fn add_session_hook(&self, key: String, hook: crate::api::SessionHook) -> bool {
+ let mut hooks = self.hooks.write().unwrap();
+ if hooks.contains_key(&key) {
+ // Already has the hook with this key.
+ return false;
+ }
+ let _ = hooks.insert(key, hook);
+ true
+ }
+
+ #[cfg(not(any(target_os = "android", target_os = "ios")))]
+ pub(crate) fn remove_session_hook(&self, key: &String) -> bool {
+ let mut hooks = self.hooks.write().unwrap();
+ if !hooks.contains_key(key) {
+ // The hook with this key does not found.
+ return false;
+ }
+ let _ = hooks.remove(key);
+ true
+ }
+
#[inline]
#[cfg(feature = "flutter_texture_render")]
pub fn register_texture(&mut self, ptr: usize) {
diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs
index a8fe66c8a..3fdc5e48f 100644
--- a/src/flutter_ffi.rs
+++ b/src/flutter_ffi.rs
@@ -844,11 +844,13 @@ fn main_broadcast_message(data: &HashMap<&str, &str>) {
pub fn main_change_theme(dark: String) {
main_broadcast_message(&HashMap::from([("name", "theme"), ("dark", &dark)]));
+ #[cfg(not(any(target_os = "ios")))]
send_to_cm(&crate::ipc::Data::Theme(dark));
}
pub fn main_change_language(lang: String) {
main_broadcast_message(&HashMap::from([("name", "language"), ("lang", &lang)]));
+ #[cfg(not(any(target_os = "ios")))]
send_to_cm(&crate::ipc::Data::Language(lang));
}
@@ -1138,6 +1140,8 @@ pub fn main_get_mouse_time() -> f64 {
}
pub fn main_wol(id: String) {
+ // TODO: move send_wol outside.
+ #[cfg(not(any(target_os = "ios")))]
crate::lan::send_wol(id)
}
@@ -1147,10 +1151,12 @@ pub fn main_create_shortcut(_id: String) {
}
pub fn cm_send_chat(conn_id: i32, msg: String) {
+ #[cfg(not(any(target_os = "ios")))]
crate::ui_cm_interface::send_chat(conn_id, msg);
}
pub fn cm_login_res(conn_id: i32, res: bool) {
+ #[cfg(not(any(target_os = "ios")))]
if res {
crate::ui_cm_interface::authorize(conn_id);
} else {
@@ -1159,22 +1165,29 @@ pub fn cm_login_res(conn_id: i32, res: bool) {
}
pub fn cm_close_connection(conn_id: i32) {
+ #[cfg(not(any(target_os = "ios")))]
crate::ui_cm_interface::close(conn_id);
}
pub fn cm_remove_disconnected_connection(conn_id: i32) {
+ #[cfg(not(any(target_os = "ios")))]
crate::ui_cm_interface::remove(conn_id);
}
pub fn cm_check_click_time(conn_id: i32) {
+ #[cfg(not(any(target_os = "ios")))]
crate::ui_cm_interface::check_click_time(conn_id)
}
pub fn cm_get_click_time() -> f64 {
- crate::ui_cm_interface::get_click_time() as _
+ #[cfg(not(any(target_os = "ios")))]
+ return crate::ui_cm_interface::get_click_time() as _;
+ #[cfg(any(target_os = "ios"))]
+ return 0 as _;
}
pub fn cm_switch_permission(conn_id: i32, name: String, enabled: bool) {
+ #[cfg(not(any(target_os = "ios")))]
crate::ui_cm_interface::switch_permission(conn_id, name, enabled)
}
@@ -1183,10 +1196,12 @@ pub fn cm_can_elevate() -> SyncReturn {
}
pub fn cm_elevate_portable(conn_id: i32) {
+ #[cfg(not(any(target_os = "ios")))]
crate::ui_cm_interface::elevate_portable(conn_id);
}
pub fn cm_switch_back(conn_id: i32) {
+ #[cfg(not(any(target_os = "ios")))]
crate::ui_cm_interface::switch_back(conn_id);
}
@@ -1222,6 +1237,7 @@ fn handle_query_onlines(onlines: Vec, offlines: Vec) {
}
pub fn query_onlines(ids: Vec) {
+ #[cfg(not(any(target_os = "ios")))]
crate::rendezvous_mediator::query_online_states(ids, handle_query_onlines)
}
diff --git a/src/hbbs_http/sync.rs b/src/hbbs_http/sync.rs
index ae91c60aa..cd7f95208 100644
--- a/src/hbbs_http/sync.rs
+++ b/src/hbbs_http/sync.rs
@@ -6,12 +6,13 @@ use hbb_common::{
};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
-
+#[cfg(not(any(target_os = "ios")))]
use crate::Connection;
const TIME_HEARTBEAT: Duration = Duration::from_secs(30);
const TIME_CONN: Duration = Duration::from_secs(3);
+#[cfg(not(any(target_os = "ios")))]
lazy_static::lazy_static! {
static ref SENDER : Mutex>> = Mutex::new(start_hbbs_sync());
}
@@ -21,10 +22,12 @@ pub fn start() {
let _sender = SENDER.lock().unwrap();
}
+#[cfg(not(target_os = "ios"))]
pub fn signal_receiver() -> broadcast::Receiver> {
SENDER.lock().unwrap().subscribe()
}
+#[cfg(not(any(target_os = "ios")))]
fn start_hbbs_sync() -> broadcast::Sender> {
let (tx, _rx) = broadcast::channel::>(16);
std::thread::spawn(move || start_hbbs_sync_async());
@@ -37,6 +40,7 @@ pub struct StrategyOptions {
pub extra: HashMap,
}
+#[cfg(not(any(target_os = "ios")))]
#[tokio::main(flavor = "current_thread")]
async fn start_hbbs_sync_async() {
tokio::spawn(async move {
diff --git a/src/lib.rs b/src/lib.rs
index a6b5c4a46..3f48be87d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -49,8 +49,10 @@ mod license;
mod port_forward;
#[cfg(not(any(target_os = "android", target_os = "ios")))]
+#[cfg(any(feature = "flutter"))]
pub mod api;
#[cfg(not(any(target_os = "android", target_os = "ios")))]
+#[cfg(any(feature = "flutter"))]
pub mod plugins;
mod tray;
diff --git a/src/main.rs b/src/main.rs
index 3759f6056..24e708c52 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,7 @@
- #![cfg_attr(
- all(not(debug_assertions), target_os = "windows"),
- windows_subsystem = "windows"
- )]
+#![cfg_attr(
+ all(not(debug_assertions), target_os = "windows"),
+ windows_subsystem = "windows"
+)]
use librustdesk::*;
diff --git a/src/platform/linux_desktop_manager.rs b/src/platform/linux_desktop_manager.rs
index 25fada503..fe60964cc 100644
--- a/src/platform/linux_desktop_manager.rs
+++ b/src/platform/linux_desktop_manager.rs
@@ -1,5 +1,5 @@
use super::{linux::*, ResultType};
-use crate::server::{
+use crate::client::{
LOGIN_MSG_DESKTOP_NO_DESKTOP, LOGIN_MSG_DESKTOP_SESSION_ANOTHER_USER,
LOGIN_MSG_DESKTOP_SESSION_NOT_READY, LOGIN_MSG_DESKTOP_XORG_NOT_FOUND,
LOGIN_MSG_DESKTOP_XSESSION_FAILED,
@@ -152,7 +152,7 @@ fn try_start_x_session(username: &str, password: &str) -> ResultType<(String, bo
desktop_manager.is_running(),
))
} else {
- bail!(crate::server::LOGIN_MSG_DESKTOP_NOT_INITED);
+ bail!(crate::client::LOGIN_MSG_DESKTOP_NOT_INITED);
}
}
diff --git a/src/plugins.rs b/src/plugins.rs
index 3235bce4a..dfbdc7753 100644
--- a/src/plugins.rs
+++ b/src/plugins.rs
@@ -36,8 +36,8 @@ pub trait Plugin {
#[repr(C)]
#[derive(Default, Clone)]
pub struct RustDeskPluginTable {
- pub init: Option,
- pub dispose: Option,
+ pub init: Option, // NonNull
+ pub dispose: Option, // NonNull
}
pub struct PluginImpl {
diff --git a/src/server/connection.rs b/src/server/connection.rs
index d4b645078..f3768aacf 100644
--- a/src/server/connection.rs
+++ b/src/server/connection.rs
@@ -65,22 +65,6 @@ lazy_static::lazy_static! {
pub static CLICK_TIME: AtomicI64 = AtomicI64::new(0);
pub static MOUSE_MOVE_TIME: AtomicI64 = AtomicI64::new(0);
-pub const LOGIN_MSG_DESKTOP_NOT_INITED: &str = "Desktop env is not inited";
-pub const LOGIN_MSG_DESKTOP_SESSION_NOT_READY: &str = "Desktop session not ready";
-pub const LOGIN_MSG_DESKTOP_XSESSION_FAILED: &str = "Desktop xsession failed";
-pub const LOGIN_MSG_DESKTOP_SESSION_ANOTHER_USER: &str = "Desktop session another user login";
-pub const LOGIN_MSG_DESKTOP_XORG_NOT_FOUND: &str = "Desktop xorg not found";
-// ls /usr/share/xsessions/
-pub const LOGIN_MSG_DESKTOP_NO_DESKTOP: &str = "Desktop none";
-pub const LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_EMPTY: &str =
- "Desktop session not ready, password empty";
-pub const LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_WRONG: &str =
- "Desktop session not ready, password wrong";
-pub const LOGIN_MSG_PASSWORD_EMPTY: &str = "Empty Password";
-pub const LOGIN_MSG_PASSWORD_WRONG: &str = "Wrong Password";
-pub const LOGIN_MSG_NO_PASSWORD_ACCESS: &str = "No Password Access";
-pub const LOGIN_MSG_OFFLINE: &str = "Offline";
-
#[derive(Clone, Default)]
pub struct ConnInner {
id: i32,
@@ -1286,13 +1270,13 @@ impl Connection {
// If err is LOGIN_MSG_DESKTOP_SESSION_NOT_READY, just keep this msg and go on checking password.
#[cfg(all(target_os = "linux", feature = "linux_headless"))]
#[cfg(not(any(feature = "flatpak", feature = "appimage")))]
- if !desktop_err.is_empty() && desktop_err != LOGIN_MSG_DESKTOP_SESSION_NOT_READY {
+ if !desktop_err.is_empty() && desktop_err != crate::client::LOGIN_MSG_DESKTOP_SESSION_NOT_READY {
self.send_login_error(desktop_err).await;
return true;
}
if !hbb_common::is_ipv4_str(&lr.username) && lr.username != Config::get_id() {
- self.send_login_error(LOGIN_MSG_OFFLINE).await;
+ self.send_login_error(crate::client::LOGIN_MSG_OFFLINE).await;
} else if password::approve_mode() == ApproveMode::Click
|| password::approve_mode() == ApproveMode::Both && !password::has_valid_password()
{
@@ -1300,7 +1284,7 @@ impl Connection {
if hbb_common::get_version_number(&lr.version)
>= hbb_common::get_version_number("1.2.0")
{
- self.send_login_error(LOGIN_MSG_NO_PASSWORD_ACCESS).await;
+ self.send_login_error(crate::client::LOGIN_MSG_NO_PASSWORD_ACCESS).await;
}
return true;
} else if password::approve_mode() == ApproveMode::Password
@@ -1339,7 +1323,7 @@ impl Connection {
if desktop_err.is_empty() {
self.try_start_cm(lr.my_id, lr.my_name, false);
} else {
- self.send_login_error(LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_EMPTY)
+ self.send_login_error(crate::client::LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_EMPTY)
.await;
}
#[cfg(not(all(target_os = "linux", feature = "linux_headless")))]
@@ -1387,15 +1371,15 @@ impl Connection {
#[cfg(all(target_os = "linux", feature = "linux_headless"))]
#[cfg(not(any(feature = "flatpak", feature = "appimage")))]
if desktop_err.is_empty() {
- self.send_login_error(LOGIN_MSG_PASSWORD_WRONG).await;
+ self.send_login_error(crate::client::LOGIN_MSG_PASSWORD_WRONG).await;
self.try_start_cm(lr.my_id, lr.my_name, false);
} else {
- self.send_login_error(LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_WRONG)
+ self.send_login_error(crate::client::LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_WRONG)
.await;
}
#[cfg(not(all(target_os = "linux", feature = "linux_headless")))]
{
- self.send_login_error(LOGIN_MSG_PASSWORD_WRONG).await;
+ self.send_login_error(crate::client::LOGIN_MSG_PASSWORD_WRONG).await;
self.try_start_cm(lr.my_id, lr.my_name, false);
}
} else {
diff --git a/src/server/video_service.rs b/src/server/video_service.rs
index e6f29a405..f7a6625ec 100644
--- a/src/server/video_service.rs
+++ b/src/server/video_service.rs
@@ -46,12 +46,6 @@ use std::{
time::{self, Duration, Instant},
};
-pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "Wayland requires Ubuntu 21.04 or higher version.";
-pub const SCRAP_OTHER_VERSION_OR_X11_REQUIRED: &str =
- "Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.";
-pub const SCRAP_X11_REQUIRED: &str = "x11 expected";
-pub const SCRAP_X11_REF_URL: &str = "https://rustdesk.com/docs/en/manual/linux/#x11-required";
-
pub const NAME: &'static str = "video";
lazy_static::lazy_static! {
diff --git a/src/server/wayland.rs b/src/server/wayland.rs
index 73a022871..10b93afce 100644
--- a/src/server/wayland.rs
+++ b/src/server/wayland.rs
@@ -3,7 +3,7 @@ use hbb_common::{allow_err, platform::linux::DISTRO};
use scrap::{is_cursor_embedded, set_map_err, Capturer, Display, Frame, TraitCapturer};
use std::io;
-use super::video_service::{
+use crate::client::{
SCRAP_OTHER_VERSION_OR_X11_REQUIRED, SCRAP_UBUNTU_HIGHER_REQUIRED, SCRAP_X11_REQUIRED,
};
diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs
index b6bb3e35d..d34b7a299 100644
--- a/src/ui_cm_interface.rs
+++ b/src/ui_cm_interface.rs
@@ -17,6 +17,7 @@ use serde_derive::Serialize;
#[cfg(not(any(target_os = "android", target_os = "ios")))]
use crate::ipc::Connection;
+#[cfg(not(any(target_os = "ios")))]
use crate::ipc::{self, Data};
#[cfg(not(any(target_os = "android", target_os = "ios")))]
use hbb_common::tokio::sync::mpsc::unbounded_channel;
@@ -56,6 +57,7 @@ pub struct Client {
pub in_voice_call: bool,
pub incoming_voice_call: bool,
#[serde(skip)]
+ #[cfg(not(any(target_os = "ios")))]
tx: UnboundedSender,
}
@@ -129,6 +131,7 @@ impl ConnectionManager {
restart: bool,
recording: bool,
from_switch: bool,
+ #[cfg(not(any(target_os = "ios")))]
tx: mpsc::UnboundedSender,
) {
let client = Client {
@@ -146,6 +149,7 @@ impl ConnectionManager {
restart,
recording,
from_switch,
+ #[cfg(not(any(target_os = "ios")))]
tx,
in_voice_call: false,
incoming_voice_call: false,
@@ -222,6 +226,7 @@ impl ConnectionManager {
}
#[inline]
+#[cfg(not(any(target_os = "ios")))]
pub fn check_click_time(id: i32) {
if let Some(client) = CLIENTS.read().unwrap().get(&id) {
allow_err!(client.tx.send(Data::ClickTime(0)));
@@ -234,6 +239,7 @@ pub fn get_click_time() -> i64 {
}
#[inline]
+#[cfg(not(any(target_os = "ios")))]
pub fn authorize(id: i32) {
if let Some(client) = CLIENTS.write().unwrap().get_mut(&id) {
client.authorized = true;
@@ -242,6 +248,7 @@ pub fn authorize(id: i32) {
}
#[inline]
+#[cfg(not(any(target_os = "ios")))]
pub fn close(id: i32) {
if let Some(client) = CLIENTS.read().unwrap().get(&id) {
allow_err!(client.tx.send(Data::Close));
@@ -255,6 +262,7 @@ pub fn remove(id: i32) {
// server mode send chat to peer
#[inline]
+#[cfg(not(any(target_os = "ios")))]
pub fn send_chat(id: i32, text: String) {
let clients = CLIENTS.read().unwrap();
if let Some(client) = clients.get(&id) {
@@ -263,6 +271,7 @@ pub fn send_chat(id: i32, text: String) {
}
#[inline]
+#[cfg(not(any(target_os = "ios")))]
pub fn switch_permission(id: i32, name: String, enabled: bool) {
if let Some(client) = CLIENTS.read().unwrap().get(&id) {
allow_err!(client.tx.send(Data::SwitchPermission { name, enabled }));
@@ -285,6 +294,7 @@ pub fn get_clients_length() -> usize {
#[inline]
#[cfg(feature = "flutter")]
+#[cfg(not(any(target_os = "ios")))]
pub fn switch_back(id: i32) {
if let Some(client) = CLIENTS.read().unwrap().get(&id) {
allow_err!(client.tx.send(Data::SwitchSidesBack));
@@ -594,6 +604,7 @@ pub async fn start_listen(
cm.remove_connection(current_id, true);
}
+#[cfg(not(any(target_os = "ios")))]
async fn handle_fs(fs: ipc::FS, write_jobs: &mut Vec, tx: &UnboundedSender) {
match fs {
ipc::FS::ReadDir {
@@ -739,6 +750,7 @@ async fn handle_fs(fs: ipc::FS, write_jobs: &mut Vec, tx: &Unbo
}
}
+#[cfg(not(any(target_os = "ios")))]
async fn read_dir(dir: &str, include_hidden: bool, tx: &UnboundedSender) {
let path = {
if dir.is_empty() {
@@ -756,6 +768,7 @@ async fn read_dir(dir: &str, include_hidden: bool, tx: &UnboundedSender) {
}
}
+#[cfg(not(any(target_os = "ios")))]
async fn handle_result(
res: std::result::Result, S>,
id: i32,
@@ -775,6 +788,7 @@ async fn handle_result(
}
}
+#[cfg(not(any(target_os = "ios")))]
async fn remove_file(path: String, id: i32, file_num: i32, tx: &UnboundedSender) {
handle_result(
spawn_blocking(move || fs::remove_file(&path)).await,
@@ -785,6 +799,7 @@ async fn remove_file(path: String, id: i32, file_num: i32, tx: &UnboundedSender<
.await;
}
+#[cfg(not(any(target_os = "ios")))]
async fn create_dir(path: String, id: i32, tx: &UnboundedSender) {
handle_result(
spawn_blocking(move || fs::create_dir(&path)).await,
@@ -795,6 +810,7 @@ async fn create_dir(path: String, id: i32, tx: &UnboundedSender) {
.await;
}
+#[cfg(not(any(target_os = "ios")))]
async fn remove_dir(path: String, id: i32, recursive: bool, tx: &UnboundedSender) {
let path = fs::get_path(&path);
handle_result(
@@ -813,6 +829,7 @@ async fn remove_dir(path: String, id: i32, recursive: bool, tx: &UnboundedSender
.await;
}
+#[cfg(not(any(target_os = "ios")))]
fn send_raw(msg: Message, tx: &UnboundedSender) {
match msg.write_to_bytes() {
Ok(bytes) => {
@@ -859,6 +876,8 @@ pub fn elevate_portable(_id: i32) {
#[inline]
pub fn handle_incoming_voice_call(id: i32, accept: bool) {
if let Some(client) = CLIENTS.read().unwrap().get(&id) {
+ // Not handled in iOS yet.
+ #[cfg(not(any(target_os = "ios")))]
allow_err!(client.tx.send(Data::VoiceCallResponse(accept)));
};
}
@@ -867,6 +886,8 @@ pub fn handle_incoming_voice_call(id: i32, accept: bool) {
#[inline]
pub fn close_voice_call(id: i32) {
if let Some(client) = CLIENTS.read().unwrap().get(&id) {
+ // Not handled in iOS yet.
+ #[cfg(not(any(target_os = "ios")))]
allow_err!(client.tx.send(Data::CloseVoiceCall("".to_owned())));
};
}
diff --git a/src/ui_interface.rs b/src/ui_interface.rs
index 3749b4918..30c6b9ab4 100644
--- a/src/ui_interface.rs
+++ b/src/ui_interface.rs
@@ -26,7 +26,10 @@ use hbb_common::{
#[cfg(feature = "flutter")]
use crate::hbbs_http::account;
-use crate::{common::SOFTWARE_UPDATE_URL, ipc};
+use crate::{common::SOFTWARE_UPDATE_URL};
+#[cfg(not(any(target_os = "ios")))]
+use crate::ipc;
+
type Message = RendezvousMessage;
@@ -569,6 +572,7 @@ pub fn create_shortcut(_id: String) {
#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))]
#[inline]
pub fn discover() {
+ #[cfg(not(any(target_os = "ios")))]
std::thread::spawn(move || {
allow_err!(crate::lan::discover());
});
@@ -922,7 +926,8 @@ pub fn option_synced() -> bool {
OPTION_SYNCED.lock().unwrap().clone()
}
-#[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))]
+#[cfg(any(target_os = "android", feature = "flutter"))]
+#[cfg(not(any(target_os = "ios")))]
#[tokio::main(flavor = "current_thread")]
pub(crate) async fn send_to_cm(data: &ipc::Data) {
if let Ok(mut c) = ipc::connect(1000, "_cm").await {
diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs
index 504982f50..db0aab0ae 100644
--- a/src/ui_session_interface.rs
+++ b/src/ui_session_interface.rs
@@ -263,7 +263,10 @@ impl Session {
}
pub fn is_xfce(&self) -> bool {
- crate::platform::is_xfce()
+ #[cfg(not(any(target_os = "ios")))]
+ return crate::platform::is_xfce();
+ #[cfg(any(target_os = "ios"))]
+ false
}
pub fn get_supported_keyboard_modes(&self) -> Vec {
@@ -526,6 +529,17 @@ impl Session {
self.send(Data::Message(msg_out));
}
+ #[cfg(any(target_os = "ios"))]
+ pub fn handle_flutter_key_event(
+ &self,
+ _name: &str,
+ platform_code: i32,
+ position_code: i32,
+ lock_modes: i32,
+ down_or_up: bool,
+ ) {}
+
+ #[cfg(not(any(target_os = "ios")))]
pub fn handle_flutter_key_event(
&self,
_name: &str,
@@ -755,6 +769,10 @@ impl Session {
self.send(Data::ElevateWithLogon(username, password));
}
+ #[cfg(any(target_os = "ios"))]
+ pub fn switch_sides(&self) {}
+
+ #[cfg(not(any(target_os = "ios")))]
#[tokio::main(flavor = "current_thread")]
pub async fn switch_sides(&self) {
match crate::ipc::connect(1000, "").await {