Migrating to AMC2¶
This page is the single reference for porting a plugin from AMC1 (the Qt 5 app, deprecated) to AMC2 (the Qt 6 app). It applies regardless of which docs version you are reading.
Who this page is for
This page is only for developers who already have a plugin that worked on AMC1 and want to make it run on AMC2. If you are writing a new plugin, ignore this page — start from the rest of these docs, which already describe the AMC2 (Qt 6) format.
Why migrate¶
AMC2 runs on Qt 6. Qt 6 changed how QML imports, asset URLs, and signal-handler arguments work, so a v1 plugin will not load correctly under AMC2 without changes.
AMC reads the apiVersion field in plugin.json to decide compatibility. AMC2 requires apiVersion 2.0 or newer, comparing only the major component. A plugin with a missing, unparseable, or below-2 apiVersion is treated as incompatible: it is copied into the Plugins folder but not loaded, shows an "Incompatible" badge in Settings → Plugins, and triggers a one-time warning dialog linking back to this guide.
So an old v1 plugin (which has no apiVersion, or used the legacy version field) will not load on AMC2 until you add "apiVersion": "2.0" and make the Qt 6 code changes below.
You can compare a full before/after for every example plugin:
- AMC1 (Qt 5) reference:
examples/v1/ - AMC2 (Qt 6) reference:
examples/v2/
Migration checklist¶
1. Declare apiVersion in plugin.json¶
If your old manifest used a version field for this purpose, rename it to apiVersion.
2. Remove version numbers from QML imports¶
Qt 6 uses versionless imports.
- import QtQuick 2.15
- import QtQuick.Controls 2.15
- import QGroundControl.Controls 1.0
+ import QtQuick
+ import QtQuick.Controls
+ import QGroundControl.Controls
3. Replace Qt.labs.settings with QtCore¶
The Settings {} type moved to the QtCore module in Qt 6.
4. Drop modules removed or restructured in Qt 6¶
Some modules no longer exist (or are not used) under Qt 6 — for example QtQuick.Extras 1.4 and QtQuick.Controls.Styles 1.4. Remove them and replace any types they provided with current equivalents. See the converted MFD imports (MFDUpperFlyView.qml) for a worked example.
5. Wrap local asset URLs in Qt.resolvedUrl(...)¶
Relative paths to bundled assets must be resolved against the QML file's location.
This applies to any local asset property (imageSource, icon.source, source, …). Absolute qrc: or /images/... paths are not affected.
6. Name implicit signal-handler arguments¶
Qt 6 no longer injects implicit arguments (like index) into signal handlers. Name them explicitly with an arrow function.
- onActivated: {
- const newVal = currentIndex
- ...
- }
+ onActivated: (index) => {
+ const newVal = index
+ ...
+ }
Shadowing gotcha
The handler's parameter can shadow an outer variable of the same name. In the MFD settings list, the delegate already had an outer index, so naming the handler param index would shadow it — the fix was to reference the delegate's index under a distinct name (mfdIndex) inside the converted handler. Watch for this when a delegate and a handler both want index.
Before / after example¶
The smallest example is FlyViewTool's tool-strip button. Full files: v1 · v2.
v1 (AMC1 / Qt 5):
import QtQuick 2.15
import QtQuick.Controls 2.15
import QGroundControl.Controls 1.0
import QGroundControl.Palette 1.0
import QGroundControl.ScreenTools 1.0
QGCHoverButton {
imageSource: "../img/hello.svg"
// ...
}
v2 (AMC2 / Qt 6):
import QtQuick
import QtQuick.Controls
import QGroundControl.Controls
import QGroundControl.Palette
import QGroundControl.ScreenTools
QGCHoverButton {
imageSource: Qt.resolvedUrl("../img/hello.svg")
// ...
}
After migrating¶
Rebuild and deploy the plugin as usual (see Building & Deploying). Load it in AMC2 and confirm it appears and behaves correctly.