Do not reuse the same `Id`/namespace you used with a widget installed with `kpackagetool5`. If a user installed it to their home directory, the code in the home directory will be loaded instead of the code in the root directory.
You cannot ship a widget that needs to be compiled on the [KDE Store](https://store.kde.org). You will need to publish it in an [Ubuntu PPA](https://help.ubuntu.com/community/PPA), on the [Arch AUR](https://aur.archlinux.org/), or with [OpenSUSE OBS](https://build.opensuse.org/).
Plasma ships with a number of useful QML plugins like PlasmaCore, PlasmaComponents, PlasmaExtras. Your widget might need more complicated models that interact with C++ libraries or File I/O requiring you to create a QML plugin.
Example Plugins
You can find a template in plasma-framework:
Download KDevelop Template
The mediaframe widget in kdeplasma-addons is a fairly simple example. The plugin has one C++ class to define the plugin, and only defines a single QML Item type.
While KDE puts `.private` in the namespace of these plugins, they can be accessed by any QML widget / application. If you plan on using someone else's "private" plugin, your widget may experience bugs when Plasma updates.
Another example is the "Kicker" plugin for the "Application Menu" widget which is reused by the kickoff "Application Launcher" widget.
To start off, let's work out what we want in the QML code. For this simple example, we will import a new WidgetItem type, which has a property named number and has an invokable function called randomize() which will set the number property to a random number.
First new things added to our CMakeLists.txt is listing all our .cpp files that we need to compile. We also define the plugin library name used in the binary filename.
In our CMakeLists.txt, we need to include a few KDE variables so that we compile and install files to the right location. Make sure the folder names match the plugin namespace.
In OpenSUSE, we'll end up installing the following files. Other distros might not use /usr/lib64/qt5 so just use locate qmldir if you are curious where the files are installed to.
Since we're now compiling Qt C++ code, we need to use find_package() to indicate that it's required for compilation. We will need Qt5::Qml to import QQmlExtensionPlugin and use qmlRegisterType(). Since we are sticking to a simple QObject in our new type, we will only need Qt5::Core.
The qmldir file is basically the qml plugin metadata file. Since we don't bundle any .qml files in the plugin itself like PlasmaComponents does, this will just define the namespace of the plugin and the plugin library name.
Inside widgetnameplugin.h we extend QQmlExtensionPlugin and indicate we implement the QQmlExtensionInterface which somehow tells it to call registerTypes().
In the .cpp file we register the new QML type. Don't forget to edit the namespace in the assert.
Finally we write our new WidgetItem type. In the header file we extend QObject and define the number property. Since we want do not want the number property to be readonly, we define WRITE and a setter function. We also define the numberChanged signal to NOTIFY the GUI when it's modified.
The plasmoid.nativeInterface property allows you to directly access C++ objects or functions in the Plasma::Applet instance. You need to extend the Plasma::Applet class first however. The plasmoid.nativeInterface cannot be accessed by another widget namespace, so this code is private.