Skip to content

Add Android device deployment flow#15146

Merged
rustdesk merged 8 commits into
rustdesk:masterfrom
21pages:deploy
Jun 2, 2026
Merged

Add Android device deployment flow#15146
rustdesk merged 8 commits into
rustdesk:masterfrom
21pages:deploy

Conversation

@21pages

@21pages 21pages commented May 30, 2026

Copy link
Copy Markdown
Collaborator

Notify the Android Flutter UI when the server requires deployment, and show the Deploy menu in Settings.

Testing

  • Android: when the device is not deployed, starting the service shows the deploy dialog. Canceling the dialog does not show it again for the same service run, and stopping then starting the service shows it again.
  • Android: deployment succeeds in the normal case. After a successful deployment, restarting the service does not show the deploy dialog again.
  • Android: when deployment is not enabled on the server, the device can register normally without showing the deploy dialog.
  • Android and desktop: other server responses and desktop deploy flows were tested, including ID_TAKEN, request failures, missing token, and custom ID deployment.
  • Android and desktop: deployment uses the same UUID and public key as normal registration, and the device can be connected after both normal registration and deployment.
Screenshot_20260530-194819 RustDesk Screenshot_20260530-194836 RustDesk Screenshot_20260530-195051 RustDesk

Summary by CodeRabbit

  • New Features

    • Device deployment flow: confirmation prompt, deploy form (API token + optional custom ID), progress handling, success toast and error messages.
    • Android: Settings shows a Deploy tile when deployment is available; the app can also prompt Android users to deploy.
  • Localization

    • Added deployment-related UI strings across many locales (placeholders; translations pending).

  Notify the Android Flutter UI when the server requires deployment, add a deploy dialog with API token/custom ID inputs, and reuse shared deploy logic
  for CLI and FFI

Signed-off-by: 21pages <sunboeasy@gmail.com>
@21pages
21pages requested a review from Copilot May 30, 2026 11:41
@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Implements device deployment end-to-end: adds DeployResult + deploy_device API client, Android one-shot "needs deploy" notification and reset, FFI entrypoint, Flutter settings tile + dialogs and event hook, CLI wiring to use DeployResult, and i18n placeholders across many locales.

Changes

Device Deployment Feature

Layer / File(s) Summary
Deployment result type and API integration
src/ui_interface.rs
DeployResult enum and deploy_device(token, new_id): validates input, POSTs to /api/devices/deploy with Bearer token, parses "result", and performs platform-specific persistence/notification on success.
Android rendezvous notification tracking
src/rendezvous_mediator.rs
Adds Android-only AtomicBool to one-shot the android_needs_deploy event, notify_android_needs_deploy() and reset_needs_deploy_notification(), triggers on NOT_DEPLOYED, resets on OK, and switches retry timestamp storage to a synchronous StdMutex.
FFI entrypoint and service initialization
src/flutter_ffi.rs
Adds pub fn main_deploy_device(token: String, id: String) -> String (Android forwards to deploy_device, others return "not supported"); Android service-start paths call reset_needs_deploy_notification() before mediator restart.
Flutter mobile UI dialogs and settings tile
flutter/lib/mobile/pages/settings_page.dart, flutter/lib/mobile/widgets/deploy_dialog.dart, flutter/lib/main.dart
Adds Android-only Deploy settings tile, showDeployPromptDialog() confirmation, and showDeployDialog() form collecting API token and optional custom ID with validation, dedupe, error display, and success flow that refreshes server ID; main registers android_needs_deploy handler.
CLI deployment command refactor
src/core_main.rs
Replaces previous manual HTTP/JSON handling for --deploy with a call to ui_interface::deploy_device() and matches DeployResult variants, printing outcome messages and exiting with specific codes.
Web bridge formatting (no behavior change)
flutter/lib/web/bridge.dart
Reflowed mainResolveAvatarUrl / mainDeployDevice formatting without behavioral changes.
Localization placeholders across languages
src/lang/*.rs (many files)
Adds deployment-related string keys (API Token, Deploy, Custom ID (optional), server_requires_deployment_tip, The server does not require explicit deployment., Unknown response.). English includes prompt text; other locales are empty placeholders.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • rustdesk

Poem

🐰 I hopped through code both wide and deep,
Tokens typed where secrets sleep.
A one-shot bell rings on Android's side,
Dialogs open, prompts decide,
Deployed at dawn — the rabbit's leap.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add Android device deployment flow' accurately and specifically describes the main changes in the PR, which focus on implementing device deployment functionality for Android platforms.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an Android device deployment flow so the Rust backend can notify Flutter when a server requires deployment, and Android users can deploy from Settings or a prompt.

Changes:

  • Refactors deployment into ui_interface::deploy_device and reuses it from CLI and Android FFI.
  • Sends an Android android_needs_deploy global event on NOT_DEPLOYED.
  • Adds Android deploy prompt/form UI plus translation keys.

Reviewed changes

Copilot reviewed 58 out of 58 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/ui_interface.rs Adds shared deployment API and result mapping.
src/core_main.rs Replaces inline CLI deploy logic with shared API.
src/rendezvous_mediator.rs Adds Android deploy notification state and event push.
src/flutter_ffi.rs Exposes Android deploy FFI and resets notification on service start.
flutter/lib/main.dart Registers Android deploy event handler.
flutter/lib/mobile/pages/settings_page.dart Adds Deploy settings entry and dialogs.
flutter/lib/web/bridge.dart Adds web stub for deploy FFI.
src/lang/en.rs Adds English deploy prompt text.
src/lang/cn.rs Adds Chinese deploy translations.
src/lang/template.rs Adds deploy translation keys.
src/lang/ar.rs Adds deploy translation placeholders.
src/lang/be.rs Adds deploy translation placeholders.
src/lang/bg.rs Adds deploy translation placeholders.
src/lang/ca.rs Adds deploy translation placeholders.
src/lang/cs.rs Adds deploy translation placeholders.
src/lang/da.rs Adds deploy translation placeholders.
src/lang/de.rs Adds deploy translation placeholders.
src/lang/el.rs Adds deploy translation placeholders.
src/lang/eo.rs Adds deploy translation placeholders.
src/lang/es.rs Adds deploy translation placeholders.
src/lang/et.rs Adds deploy translation placeholders.
src/lang/eu.rs Adds deploy translation placeholders.
src/lang/fa.rs Adds deploy translation placeholders.
src/lang/fi.rs Adds deploy translation placeholders.
src/lang/fr.rs Adds deploy translation placeholders.
src/lang/ge.rs Adds deploy translation placeholders.
src/lang/gu.rs Adds deploy translation placeholders.
src/lang/he.rs Adds deploy translation placeholders.
src/lang/hi.rs Adds deploy translation placeholders.
src/lang/hr.rs Adds deploy translation placeholders.
src/lang/hu.rs Adds deploy translation placeholders.
src/lang/id.rs Adds deploy translation placeholders.
src/lang/it.rs Adds deploy translation placeholders.
src/lang/ja.rs Adds deploy translation placeholders.
src/lang/ko.rs Adds deploy translation placeholders.
src/lang/kz.rs Adds deploy translation placeholders.
src/lang/lt.rs Adds deploy translation placeholders.
src/lang/lv.rs Adds deploy translation placeholders.
src/lang/ml.rs Adds deploy translation placeholders.
src/lang/nb.rs Adds deploy translation placeholders.
src/lang/nl.rs Adds deploy translation placeholders.
src/lang/pl.rs Adds deploy translation placeholders.
src/lang/pt_PT.rs Adds deploy translation placeholders.
src/lang/ptbr.rs Adds deploy translation placeholders.
src/lang/ro.rs Adds deploy translation placeholders.
src/lang/ru.rs Adds deploy translation placeholders.
src/lang/sc.rs Adds deploy translation placeholders.
src/lang/sk.rs Adds deploy translation placeholders.
src/lang/sl.rs Adds deploy translation placeholders.
src/lang/sq.rs Adds deploy translation placeholders.
src/lang/sr.rs Adds deploy translation placeholders.
src/lang/sv.rs Adds deploy translation placeholders.
src/lang/ta.rs Adds deploy translation placeholders.
src/lang/th.rs Adds deploy translation placeholders.
src/lang/tr.rs Adds deploy translation placeholders.
src/lang/tw.rs Adds deploy translation placeholders.
src/lang/uk.rs Adds deploy translation placeholders.
src/lang/vi.rs Adds deploy translation placeholders.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/rendezvous_mediator.rs
Comment thread flutter/lib/mobile/pages/settings_page.dart Outdated
Signed-off-by: 21pages <sunboeasy@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 58 out of 58 changed files in this pull request and generated no new comments.

Signed-off-by: 21pages <sunboeasy@gmail.com>
@rustdesk

rustdesk commented Jun 1, 2026

Copy link
Copy Markdown
Owner

• The Android deployment flow has a state-reset bug that can delay or suppress the deploy prompt after a stop/start cycle. This breaks a user-visible behavior introduced by the patch.

Review comment:

  • [P2] Reset deploy backoff when restarting Android service — /Users/hzhou/rustdesk/src/rendezvous_mediator.rs:86-88
    When a device has just received NOT_DEPLOYED, stopping and immediately starting the Android service only clears NOTIFIED_NEEDS_DEPLOY; NEEDS_DEPLOY and LAST_NOT_DEPLOYED_REGISTER remain set, so
    deploy_register_throttled()/register_pk() suppress the next registration until DEPLOY_RETRY_INTERVAL expires. This means the prompt will not reappear on the next service run for up to 30 seconds,
    contrary to the intended restart behavior.

21pages added 3 commits June 1, 2026 12:02
Signed-off-by: 21pages <sunboeasy@gmail.com>
Signed-off-by: 21pages <sunboeasy@gmail.com>
Signed-off-by: 21pages <sunboeasy@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
flutter/lib/mobile/pages/settings_page.dart (1)

731-737: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep the Deploy tile gated on the Android service state.

Line 731 now shows this entry for every Android non-outgoing-only client, but the intended behavior for this flow is to expose Deploy only while the service is running. Without the gFFI.serverModel.isStart guard, users can open a deploy action from the stopped-service state.

Suggested fix
-          if (isAndroid && !bind.isOutgoingOnly())
+          if (isAndroid && gFFI.serverModel.isStart && !bind.isOutgoingOnly())
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@flutter/lib/mobile/pages/settings_page.dart` around lines 731 - 737, The
Deploy SettingsTile is currently shown for any Android non-outgoing-only client;
wrap the tile rendering condition to also require the service to be running by
adding a guard using gFFI.serverModel.isStart (i.e., only show the SettingsTile
when isAndroid && !bind.isOutgoingOnly() && gFFI.serverModel.isStart), so the
SettingsTile (and its onPressed that calls showDeployDialog) is only available
while the Android service is started.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@flutter/lib/mobile/pages/settings_page.dart`:
- Around line 731-737: The Deploy SettingsTile is currently shown for any
Android non-outgoing-only client; wrap the tile rendering condition to also
require the service to be running by adding a guard using
gFFI.serverModel.isStart (i.e., only show the SettingsTile when isAndroid &&
!bind.isOutgoingOnly() && gFFI.serverModel.isStart), so the SettingsTile (and
its onPressed that calls showDeployDialog) is only available while the Android
service is started.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 240b3776-ba44-434b-ba07-ac54f631b0fa

📥 Commits

Reviewing files that changed from the base of the PR and between 2045c26 and 72e5b78.

📒 Files selected for processing (55)
  • flutter/lib/mobile/pages/settings_page.dart
  • src/core_main.rs
  • src/lang/ar.rs
  • src/lang/be.rs
  • src/lang/bg.rs
  • src/lang/ca.rs
  • src/lang/cn.rs
  • src/lang/cs.rs
  • src/lang/da.rs
  • src/lang/de.rs
  • src/lang/el.rs
  • src/lang/en.rs
  • src/lang/eo.rs
  • src/lang/es.rs
  • src/lang/et.rs
  • src/lang/eu.rs
  • src/lang/fa.rs
  • src/lang/fi.rs
  • src/lang/fr.rs
  • src/lang/ge.rs
  • src/lang/gu.rs
  • src/lang/he.rs
  • src/lang/hi.rs
  • src/lang/hr.rs
  • src/lang/hu.rs
  • src/lang/id.rs
  • src/lang/it.rs
  • src/lang/ja.rs
  • src/lang/ko.rs
  • src/lang/kz.rs
  • src/lang/lt.rs
  • src/lang/lv.rs
  • src/lang/ml.rs
  • src/lang/nb.rs
  • src/lang/nl.rs
  • src/lang/pl.rs
  • src/lang/pt_PT.rs
  • src/lang/ptbr.rs
  • src/lang/ro.rs
  • src/lang/ru.rs
  • src/lang/sc.rs
  • src/lang/sk.rs
  • src/lang/sl.rs
  • src/lang/sq.rs
  • src/lang/sr.rs
  • src/lang/sv.rs
  • src/lang/ta.rs
  • src/lang/template.rs
  • src/lang/th.rs
  • src/lang/tr.rs
  • src/lang/tw.rs
  • src/lang/uk.rs
  • src/lang/vi.rs
  • src/rendezvous_mediator.rs
  • src/ui_interface.rs
✅ Files skipped from review due to trivial changes (15)
  • src/lang/template.rs
  • src/lang/ca.rs
  • src/lang/pt_PT.rs
  • src/lang/he.rs
  • src/lang/gu.rs
  • src/lang/el.rs
  • src/lang/hi.rs
  • src/lang/ptbr.rs
  • src/lang/sl.rs
  • src/lang/tw.rs
  • src/lang/fi.rs
  • src/lang/ar.rs
  • src/lang/lv.rs
  • src/lang/lt.rs
  • src/lang/eo.rs
🚧 Files skipped from review as they are similar to previous changes (19)
  • src/lang/th.rs
  • src/core_main.rs
  • src/lang/tr.rs
  • src/lang/vi.rs
  • src/lang/fa.rs
  • src/lang/kz.rs
  • src/lang/be.rs
  • src/lang/es.rs
  • src/lang/ro.rs
  • src/lang/et.rs
  • src/lang/sv.rs
  • src/lang/id.rs
  • src/lang/eu.rs
  • src/lang/ml.rs
  • src/lang/it.rs
  • src/lang/fr.rs
  • src/ui_interface.rs
  • src/lang/ru.rs
  • src/lang/de.rs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 58 out of 58 changed files in this pull request and generated 2 comments.

Comment thread flutter/lib/web/bridge.dart
Comment thread flutter/lib/main.dart
Signed-off-by: 21pages <sunboeasy@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
flutter/lib/mobile/widgets/deploy_dialog.dart (1)

65-69: 💤 Low value

Redundant toString() on a String.

res is already a String, so res.toString() is a no-op; pass res directly.

♻️ Proposed tweak
-          errorText = translate(res.toString());
+          errorText = translate(res);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@flutter/lib/mobile/widgets/deploy_dialog.dart` around lines 65 - 69,
Redundant toString() on a String: in the setState block where errorText is
assigned, replace translate(res.toString()) with translate(res) and keep
isInProgress = false unchanged. Update only the assignment to errorText, using
the existing variables res, errorText, isInProgress, and the translate() call
for easy location.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@flutter/lib/mobile/widgets/deploy_dialog.dart`:
- Around line 30-35: showDeployDialog creates TextEditingController instances
(tokenController, idController) but never disposes them, leaking resources;
update showDeployDialog to dispose both controllers after the dialog completes
by awaiting the dialog future and calling tokenController.dispose() and
idController.dispose() in a finally/whenComplete block so disposal happens
whether the dialog was accepted or cancelled; reference tokenController,
idController and the show dialog call inside showDeployDialog to locate where to
await the future and run the disposals.

---

Nitpick comments:
In `@flutter/lib/mobile/widgets/deploy_dialog.dart`:
- Around line 65-69: Redundant toString() on a String: in the setState block
where errorText is assigned, replace translate(res.toString()) with
translate(res) and keep isInProgress = false unchanged. Update only the
assignment to errorText, using the existing variables res, errorText,
isInProgress, and the translate() call for easy location.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 41491f49-051c-4b6a-97b9-ccb80c715841

📥 Commits

Reviewing files that changed from the base of the PR and between 72e5b78 and d35e531.

📒 Files selected for processing (3)
  • flutter/lib/main.dart
  • flutter/lib/mobile/pages/settings_page.dart
  • flutter/lib/mobile/widgets/deploy_dialog.dart

Comment thread flutter/lib/mobile/widgets/deploy_dialog.dart

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 59 out of 59 changed files in this pull request and generated 5 comments.

Comment thread src/lang/template.rs
Comment thread src/rendezvous_mediator.rs
Comment thread src/rendezvous_mediator.rs Outdated
Comment thread src/rendezvous_mediator.rs Outdated
Comment thread src/rendezvous_mediator.rs Outdated
Signed-off-by: 21pages <sunboeasy@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 59 out of 59 changed files in this pull request and generated 4 comments.

Comment thread src/ui_interface.rs
Comment thread src/ui_interface.rs
Comment thread flutter/lib/web/bridge.dart
Comment thread src/lang/template.rs
@rustdesk
rustdesk merged commit d99ddf6 into rustdesk:master Jun 2, 2026
20 checks passed
rustdesk pushed a commit that referenced this pull request Jul 20, 2026
…5633)

`rustdesk --deploy --id ""` (e.g. an unset variable in a deployment
script) deploys a blank id, then wipes the local id and unconfirms the
key through the IPC config write. The Android deploy flow already guards
an empty id (#15146); apply the same guard to the CLI, and reject an
empty id at the IPC write boundary the same way the read path was fixed
in #15626.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants