CommunityProductivity & Collaborationgithub.com

Tiecode Plugin Development Skills

A comprehensive guide to developing plugins for Tiecode (Tiecode IDE / QiStudio). It covers the plugin API (com.rapid.api.* / studio-api.jar), extension points in program.json, .rmx packaging, and various implementation approaches for features like code completion, file tree, run configurations, project templates, build tasks, toolchains, syntax highlighting, menus, and settings pages. Use this skill when developing, modifying, learning, or debugging Tiecode plugins, Tiecode IDE plugins, .rmx plugins, or language engineering plugins for Go, Scala, Kotlin, Linux, AAR, etc.

What is Tiecode Plugin Development Skills?

This skill provides a complete guide for developing plugins for Tiecode IDE (QiStudio), a modular mobile IDE that uses the OSGi standard. You can use it to understand the entire plugin architecture: from the plugin SDK (com.rapid.api.*) and extension points (declared in META-INF/program.json) to practical implementation examples for key features. The skill includes real-world code examples for creating project managers, language engines with LSP and TextMate highlighting, build tasks with customizable toolchains, run configurations, file tree integrations, and project templates. It is essential for developers who need to create, modify, or troubleshoot plugins for Tiecode (and its successor QiStudio) or wish to extend the IDE with support for new programming languages (like Go, Scala, Kotlin, or Linux) or custom build processes. The documentation is based on decompiling the studio-api-1.0-preview5.jar and analyzing over a dozen real-world plugins from Gitee and GitHub repositories.

Works with~Claude Code~Codex CLI✓Cursor
npx skills add boboyr/TiecodePluginSkills

Installed? Explore more Productivity & Collaboration skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Tiecode Plugin Development

Plugin development documentation for Tiecode IDE / QiStudio (host package name com.tiecode.develop). The official name of Tiecode Studio is QiStudio (a new generation open engineering platform, the first mobile app to implement the OSGi standard, extending the engineering development environment through 'micro-components/plugins'). Content source: Decompiled studio-api-1.0-preview5.jar (com.rapid.api.*) + reverse-engineered source code of over a dozen real plugins (Go, Scala, Kotlin, Linux, AAR, LibGDX, No-install run, etc.).


Official Resources and Repositories (Important)

Official Gitee Repositories

RepositoryDescription
MobileIPE-Plugin-DevManualOfficial plugin development tutorial (QiStudio micro-components). Includes QiStudio核心体系介绍.md, Rapid框架介绍.md, plugin/扩展点介绍.md, plugin/插件清单配置.md, plugin/注册你的微组件——插件.md
TiecodeCompiler-PublicTiecode Compiler (Cross-platform version) product release repository. Includes docs/ (compiler usage/grammar/packaging/platform integration docs), headers/tiec/ (C API + C++ wrapper headers), prebuilt/ (CLI + android/windows/linux/ohos/wasm dynamic libraries), stdlibs/ (Android/CXX/Web basic libraries)
QiStudio-PluginSamplesOfficial plugin sample projects (19+ examples: dependency injection, editor animation/rainbow brackets, floating log window, HTML project manager, network requests, icon extensions, Javac9 toolchain, syntax highlighting, custom themes, Application lifecycle, project components, various menus, tool pages, settings pages, etc.)

The official API jar is named qistudio-api-<version>.jar (the studio-api-1.0-preview5.jar decompiled in this skill is its host-side SDK). QQ Community: 1016399857.

Community Reference Implementations (GitHub)

Set of real plugin source code (single repo, multiple directories, containing 8 complete compilable plugins) accompanying this skill:

https://github.com/boboyr/tiecode-plugin

DirectoryPluginDemonstrated Capabilities
go语言工程插件/Go language engineering (Console+SDL3)Dual templates + LSP(gopls) completions + TextMate highlighting + Toolchain + Run configuration + File tree virtual nodes
结绳安卓工程aar构建插件/AAR/JAR buildingReuse host compiler chain + NameGenerator Chinese output
结绳免安装运行插件/No-install runnerReuse host tasks + Plugin-based loading of uninstalled APKs
libgdx游戏编辑器插件/LibGDX visual editorDesigner + Editor code area menu + New scene classes
scala安卓工程插件/Scala Android engineeringFull sbt build chain + 'Tiecode Plugin Project' template + Build/Debug plugins
结绳Linux工程插件/Tiecode Linux-SDL3GCC toolchain + SDL3 + Task chains
外部kotlin文件注解插件/External Kotlin file annotationsTiecode Compiler API: CompilerPlugin + AnnotationProcessor + Kotlin completions
BasicLanguages-lang参考/Official basic languagesCSML/JSON/Markdown/XML/Properties syntax highlighting reference

0. Core Concepts and Overall Architecture

Tiecode is a modular IDE host. Plugins are distributed as .rmx files. A .rmx is essentially an APK: AndroidManifest.xml + classes.dex + META-INF/program.json. The host discovers plugin capabilities through extension points declared in program.json, rather than relying on manifest <application> or the four major components.

0.1 Three Key Packages

PackageRole
com.rapid.api.*Plugin SDK (main subject of this document). Engineering, Language, Tasks, Structure, Pages, UI, Networking, etc.
com.rapid.framework.*Framework layer: VFS (Virtual File System), Service/Data/Event Keys, program/plugin container
com.tiecode.compiler.*Tiecode Compiler (AST / Symbol Table / Toolchain completer/processor) – host-side, plugins generally only use its toolchain subpackage

0.2 Extension Points (extension array in program.json)

Full structure of META-INF/program.json:

{
  "id": "com.goproject.plugin",
  "name": "Go语言工程插件",
  "engine": "plugin",
  "description": "...",
  "versionCode": 4,
  "versionName": "1.3",
  "minSupport": 1,
  "vendor": { "name": "boboyr", "email": "", "url": "#" },
  "extension": [
    { "point": "application", "class": "com.goproject.plugin.MyApplication" },
    { "point": "project.manager", "class": "com.goproject.plugin.project.GoProjectManager" },
    { "point": "project.language", "class": "com.goproject.plugin.lang.GoLanguageFactory",
      "scope": { "unit": "project", "identifiers": "sample.go" } },
    { "point": "domain.menu", "class": "com.goproject.plugin.Gomodmenu" }
  ]
}

minSupport Field Description (Minimum Supported Host Version)

minSupport is an integer indicating the minimum Tiecode version required by the plugin. Different versions have different values:

Tiecode VersionminSupportDescription
Tiecode 4.61Plugins for 4.6 should use "minSupport": 1
Tiecode 4.72Plugins for 4.7 should use "minSupport": 2

That is: when developing for 4.6, set minSupport to 1; when upgrading to 4.7 (or developing for 4.7), set it to 2. The specific rules mapping values to host versions are official; just fill in according to the target host version when developing.

Confirmed complete list of extension points (point field):

Extension PointClass to Implement/ExtendRoleSource Plugin
applicationAndroidPluginPlugin entry point, onInit/activate/onUninstallGo/Scala/AAR/No-install
project.managerProjectManager (commonly CodeProjectManager)Register a project typeGo/Scala/Linux
project.languageLanguageFactoryRegister a language (highlighting + associated file extensions), can have scopeGo/Scala
project.language.engineLanguageEngineRegister a language engine (container for completions/diagnostics providers)Tiecode Console Plugin
project.toolchainTool subclass (e.g., SunJdk8Compiler)Register a build toolchainJavaCompiler8
project.componentComponentIntegrator/ComponentFactoryMount components when opening a project (run configurations/first-run popups/hooks)Linux/Kotlin/AAR/No-install
project.file.creationOptionPSObjectCreationOption'New File' menu item in file treeKotlin/LibGDX
project.file.openWithEditorPSObjectOpeningOptionFile 'Open With' optionsKotlin
project.event.fileUiProjectFileUiEventFile tree UI events (e.g., binding icons)Kotlin
domain.menuBaseDomainMenuAction/menu actionTop-level menu itemsGo
domain.menu.editor.codeCode editor area menuLibGDX
platform.settingsBuilderSettingsBuilderAdd new sub-pages to settingsScala Android
project.file.creationOption———

Note: scope.identifiers is used to restrict a language/component to a specific project typeId (e.g., sample.go). Some extension point classes can be None (placeholder).


1. Plugin Entry Point: application Extension Point

import com.rapid.framework.program.android.app.AndroidPlugin;
import com.rapid.framework.program.android.DvmPluginDescriptor;
import com.rapid.api.Platform;
import com.rapid.api.framework.project.toolchain.ToolchainService;
import com.rapid.api.framework.project.ProjectServiceKeys;

public class MyApplication extends AndroidPlugin {
    @Override
    public void onInit(DvmPluginDescriptor descriptor) {
        // Register a custom build toolchain (example: Go compiler)
        ToolchainService service = Platform.getService(ProjectServiceKeys.TOOLCHAIN);
        service.setTool(GoCompileApiKeys.Gocompile, new BaseGoCompiler());
    }
    @Override
    public void activate() {
        // Executed once when the plugin is activated (often for hooks, listeners, assembling compilation plugins)
    }
    @Override
    public void onUninstall() {
        // Clean up: terminate child processes (e.g., gopls), disconnect LSP
    }
}

Key API (com.rapid.api.Platform):

  • Platform.getService(Key<T>) — Get a host service (e.g., ProjectServiceKeys.TOOLCHAIN)
  • Platform.getProject() — Get the currently open project object
  • Platform.getApplicationContext() — Get the host Context

2. Project Type: project.manager Extension Point

A plugin registers a 'project type' (e.g., Go语言工程, Tiecode Android Project) via ProjectManager.

2.1 Manager Skeleton

public class GoProjectManager extends CodeProjectManager<GoProject> {
    public final static String TYPE = "Go语言工程";       // Display name
    public final static String IDENTIFIER = "sample.go"; // typeId, stored in project.json

    public GoProjectManager() {
        super();
        this.fileManager = new GoFileManager();   // Optional: custom file manager (bind icons, etc.)

        // ① File open methods (by extension)
        fileManager.addPSObjectOpeningOption(DefaultOpeningOption.INSTANCE, ".go", ".mod");
        // ② File tree node expansion methods (virtual 'External Libraries' node)
        fileManager.addPSObjectExpansionCase(new ExternalLibrariesExpansionCase(), MARKER);
        // ③ New file menu items
        fileManager.addPSObjectCreationOption(new GoFileCreationOption());
        // ④ Language engine and language factory
        languageManager.registerEngine("go", GoLanguageEngine.getInstance());
        languageManager.registerLanguageFactory(new GoLanguageFactory());
        languageManager.registerOperatorProvider(GoLanguage.ID, new GoOperatorProvider());
        // ⑤ Project creation templates
        addTemplate(new GoConsoleTemplate());
        addTemplate(new GoSdl3Template());
    }

    @Override public String getIdentifier() { return IDENTIFIER; }

    @Override public TypeDescription getTypeDescription() {
        Drawable d = ContextUtils.getDrawable(AndroidPlugins.getContext(this), R.drawable.golang);
        return new TypeDescription(TYPE, TypeDescription.APPLICATION, d);
    }

    @Override public GoProject newProject() { return new GoProject(); }

    @Override public boolean isProjectDir(File file) { return false; }
}

ProjectManager interface methods (from javap):

String getIdentifier();
TypeDescription getTypeDescription();      // Name + Type + Icon
List<Template<T>> getTemplates();
void addTemplate(Template<T>);
ProjectFileManager<T> getFileManager();
T newProject();
void load(T, LoadingPresentation);
boolean isProjectDir(File);                // Determine if a directory is of this project type
String backup(T); void delete(T);

TypeDescription type constants: APPLICATION / CONSOLE / LIBRARY.


3. Project Object and Pipeline Assembly: CodeProject.prepare()

Each project type corresponds to a Project subclass. prepare() is called by the host when opening a project. At this point, template files have been written, and you can assemble task chains, run configurations, and components based on the directory contents.

public class GoProject extends CodeProject {
    @Override
    public void prepare() {
        if (GoProjectKind.isSdl3(getProjectDir())) {
            Task buildLibmain = new BuildLibmainTask();
            Task publishLib = new PublishLibTask();
            addTask(buildLibmain);
            addTask(publishLib);
            publishLib.dependsOn(buildLibmain);      // Task dependency
            addRunConfiguration(new GoSdl3RunConfiguration());
        } else {
            addTask(new CompilerGoTask());
            addTask(new RunGoTask());
            addRunConfiguration(new GoStartRunConfig());
            addRunConfiguration(new ElfRunConfig());
        }
    }
    @Override public ProjectVariant getVariant() { return ProjectVariant.DEBUG; }
}

Key methods of CodeProject (extends BaseProject):

void prepare();
TaskContainer getTasks();  TaskExecutor getTaskExecutor();
void addTask(Task);  void setTasks(Iterable<Task>);
void addRunConfiguration(RunConfiguration);   // CodeProject only
ProjectVariant getVariant();  void setVariant(ProjectVariant);
Logger getLogger();  void setLogger(Logger);
String getName();
File getProjectDir();  File getChildFile(String);   // Resolve a relative project path to a File
void recycle();

ProjectVariant values: DEBUG / RELEASE / UNDEFINED.

Tip (from Go plugin): In prepare(), you can write marker files (e.g., External Libraries) to the project to retroactively add capabilities to existing old projects without needing to recreate them.


4. Project Templates: BaseTemplate

Templates determine the options available in the 'New Project' dialog and which files to write upon creation.

public class GoConsoleTemplate extends BaseTemplate<GoProject> {
    @Override public String getName() { return "Console Project"; }
    @Override public Drawable getPicture() { return null; }        // Template preview image, can be null
    @Override public String getDefaultProjectName() { return "MyGoConsoleProject"; }
    @Override public Form getForm() { return new Form(); }         // Can add input fields

    @Override public void create(GoProject project, Form form,
                                 Project.OnProjectCreateListener listener) {
        try {
            File file = project.getChildFile("src/main.go");
            String html = AssetUtils.readAsset(AndroidPlugins.getContext(this), "sample/main.go");
            html = html.replace("${project_name}", project.getName());
            FileUtils.writeFile(html, file);                        // Write to project directory
            FileUtils.writeFile("module main\ngo 1.26.0", project.getChildFile("src/go.mod"));
            listener.onSuccess();                                    // Success callback
        } catch (IOException e) {
            listener.onFail("Failed to write default files");       // Failure callback
        }
    }
}

Template<T> interface methods:

String getName();
Drawable getPicture();
String getDefaultProjectName();
Form getForm();          // com.rapid.framework.data.form.Form, can addInput(new FormInput(...))
void create(T, Form, OnProjectCreateListener);   // OnProjectCreateListener.onSuccess()/onFail(msg)

Resources in Templates: Place template files in app/src/main/assets/<name>, and read/extract them using AssetUtils.readAsset / AssetUtils.unZipAssetsFolder(context, zipName, destDir). (The SDL3 project template, for example, uses the gosdl3_template.zip in assets which is extracted entirely to the project directory.)


5. Build Tasks and Toolchains: BaseTask + ToolchainService

5.1 Task BaseTask

public class CompilerGoTask extends BaseTask {
    @Override public void execute() throws TaskInterruptError {
        File output = new File(Platform.getProject().getProjectDir() + "/output");
        if (!output.exists()) output.mkdirs();
        GoCompile a = Platform.getService(ProjectServiceKeys.TOOLCHAIN)
                             .getTool(GoCompileApiKeys.Gocompile);
        if (!a.isInstalled(ctx)) { logger.info("Installing toolchain..."); a.install(ctx); }
        GoCompileParams p = new GoCompileParams();
        p.inputFiles = FileUtils.getGofile(srcDir);
        p.outputPath = output.getPath();
        p.options = new String[]{"build", "-o"};
        a.compile(p, new CompileOnExecutionCallback());
    }

    // Must override: default BaseTask.prepare throws UnsupportedOperationException;
    // also, logger/variant fields must be assigned here, otherwise logger.info in execute() will NPE.
    @Override public void prepare(Project project, ProjectVariant variant, Logger logger) {
        this.logger = logger;
        this.variant = variant;
        Os.setenv("GOROOT", goRoot, false);   // Set environment variables (android.system.Os)
    }

    @Override public String getId() { return "compileWithGo"; }   // Referenced by run configuration's getTaskId()
    @Override public String getName() { return "Compile to target platform"; }
}

Task interface (from javap):

String getId();  String getName();
void prepare(Project, ProjectVariant, Logger);      // Note: default throws exception, must override
void execute() throws TaskInterruptError;
TaskState getState();
void interrupt();
void dependsOn(Task...);  void dependsOn(List<Task>);
Task getDependencyTask(String);  Task getDependencyTaskByName(String);
String getIntermediatePath();  String getIntermediatePath(String);
String getOutputPath();  String getOutputPath(String);
File getGeneratedDir();

Pitfall (from Go plugin comments): If logger is not assigned in the task, using logger.info in execute() will cause an NPE and fail immediately, so the toolchain installation will never execute.

5.2 Toolchain Tool + Installable

public interface Tool { /* Built-in keys: ANDROID_SDK/AAPT/AAPT2/D8/R8/DX/PROGUARD/
                         MANIFEST_MERGER/APK_SIGNER/JAVA_SDK/JAVA_COMPILER, etc. */ }
public interface Installable {
    boolean isInstalled(Context);
    void install(Context) throws IOException;
}
  • Register a custom toolchain in application.onInit() using ToolchainService.setTool(customKey, impl).
  • Built-in Android toolchain keys are all in the Tool interface (you can directly use Platform.getService(TOOLCHAIN).getTool(Tool.AAPT2)).
  • To reuse the host's compiler chain (as done by the AAR plugin / No-install plugin): do not bundle the compiler yourself; instead, use getDependencyTaskByName("compileWithTiecodec") to get the host task and add a dependency, or directly reuse getTaskId().

6. Run Configurations: RunConfiguration / TaskRunConfiguration

Add executable items to the project's 'Run' menu. The most commonly used is TaskRunConfiguration: specify a task ID, and the onResult callback is triggered upon successful execution.

public class GoStartRunConfig extends TaskRunConfiguration {
    public Project getProject() { return Platform.getProject(); }
    public String getTaskId() { return "RunWithGo"; }          // Associated task ID
    public ProjectVariant getVariant() { return ProjectVariant.DEBUG; }
    public String getName() { return "Run"; }

    @Override
    public void onResult(TaskResult result) {
        if (result.getTaskState() == TaskState.SUCCESS) {
            // Launch the generated executable
            getProject().getLogger().info("Run successful");
        }
    }
}

RunConfiguration interface (from javap):

String getName();
Project getProject();
ProjectVariant getVariant();
void run();                                     // Called when the user clicks the run button
void interrupt();
void onResult(TaskResult);                       // Callback after task chain execution
TaskResult getResult();

Tip: In the Linux plugin, TaskRunConfiguration is used to run SDL3 programs after a GCC compilation completes. In the AAR plugin, a custom RunConfiguration is used to write the build product path into project.json.


7. Language Features: LSP Completions + TextMate Highlighting + Tokenizer

7.1 LanguageEngine Architecture

LanguageEngine is a container for CompletionProvider, DiagnosticsProvider, TokenSet, etc.

public class GoLanguageEngine extends LanguageEngine {
    private static GoLanguageEngine instance = new GoLanguageEngine();
    public static GoLanguageEngine getInstance() { return instance; }

    private GoLanguageEngine() {
        // 1. Create a source file/class path tokenizer
        addTokenSet(GoTokenSets.IMPORT_PATH);
        addTokenSet(GoTokenSets.PACKAGE);

        // 2. Register LSP completion provider (gopls)
        addCompletionProvider(new GoLspCompletionProvider());

        // 3. Register diagnostics provider (optional, e.g., import error checking)
        addResourceResolver(new GoResourceResolver());
    }
}

7.2 TextMate Grammar-Based Highlighting (.tmLanguage.json)

Reference: BasicLanguages-lang official sample. Parse the JSON grammar file into a StringMap grammar:

public class GoLanguageFactory extends LanguageFactoryBase {
    @Override public void init() {
        // Load textmate grammar from assets
        String grammarJson = AssetUtils.readAsset(context, "textmate/go.json");
        grammar = new TextMateProcessTokenGrammar();
        grammar.load(grammarJson);  // Parse JSON grammar
    }
    @Override public TextMateProcessTokenGrammar getGrammar() { return grammar; }
}

The official BasicLanguages-lang sample uses TextMateProcessTokenGrammar directly. Community plugins also support:

  • TokenProcessor chain: parse token nodes into
  • OperatorProvider: Provide an operator list (used for auto-pairing, indent guides)
  • CompletionProvider based on CharacterIndicesCompletionProvider: static keyword completion

7.3 LSP Client

Core classes for LSP support in the Go plugin:

import com.rapid.api.feature.lsp.*;

public class GoLspCompletionProvider extends LspCompletionProvider {
    @Override protected LspServer createServer() {
        return new GoLspServer();
    }
}

public class GoLspServer extends LspServer {
    private Process lspProcess;

    @Override protected void start() throws IOException {
        // Start gopls subprocess
        lspProcess = new ProcessBuilder("gopls", "-mode=stdio")
            .directory(getProjectDir())
            .start();
        super.setInputStream(lspProcess.getInputStream());
        super.setOutputStream(lspProcess.getOutputStream());
    }

    @Override protected void stop() {
        if (lspProcess != null) lspProcess.destroy();
    }

    // Override initialize to pass workspace folders, capabilities, etc.
    @Override protected InitializeResult initialize() {
        // Set LSP init params: rootUri, capabilities, etc.
        return super.initialize();
    }
}

Note: LSP support requires the plugin to manage the lifecycle of the LSP subprocess. The clean-up logic (stopping gopls) must be placed in onUninstall() of AndroidPlugin.


8. File Tree: Virtual Nodes (PSObject/ExpansionCase/CreationOption/OpeningOption)

8.1 Virtual Nodes (ExpansionCase)

Add a virtual node like 'External Libraries' below the project root, with the actual subtree being dynamically generated by querying the file system or a package manager:

public class ExternalLibrariesExpansionCase implements PSObjectExpansionCase {
    // Referenced in fileManager.addPSObjectExpansionCase() with MARKER constant
    @Override public List<? extends PSObject> computeChildren(@NotNull PSObject parent) {
        List<PSObject> children = new ArrayList<>();
        File libDir = new File(parent.getFile(), "lib");
        if (libDir.exists()) {
            for (File jar : libDir.listFiles((dir, name) -> name.endsWith(".jar"))) {
                children.add(new PSObjectFile(jar));  // Each jar as a file node under the virtual folder
            }
        }
        return children;
    }

    @Override public String getName() { return "External Libraries"; }
    @Override public Icon getIcon() { return Icon.CLASSPATH; }
}

8.2 New File Menu (CreationOption)

public class GoFileCreationOption implements PSObjectCreationOption {
    @Override public List<String> getSupportedExtensions() {
        return Arrays.asList(".go", ".mod");
    }

    @Override public List<String> getFileTemplates() {
        return Arrays.asList("main.go", "util.go");
    }

    @Override public boolean isAvailable(@NotNull PSObject context) {
        return context instanceof PSODirectory; // Only show in directories
    }

    @Override public void execute(@NotNull PSObject context, @Nullable String template) {
        // Create a new .go file in the target directory
        File newFile = new File(context.getFile(), "new_file.go");
        FileUtils.writeFile("package main\n", newFile);
    }
}

8.3 Opening Options (OpeningOption)

Control how a file is opened in an editor (e.g., double-click on .mod opens text editor, not the design view):

public class ModOpeningOption implements PSObjectOpeningOption {
    @Override public boolean canOpen(@NotNull PSObject psObject) {
        return psObject.getFile().getName().endsWith(".mod");
    }

    @Override public void open(@NotNull PSObject psObject) {
        // Open in the default text editor
        Platform.getEditorManager().openTextEditor(psObject.getFile());
    }
}

9. Menus: domain.menu Extension Point

Add top-level menu items to the IDE's main menu bar:

public class GoMenuAction extends BaseDomainMenuAction {
    @Override public String getName() { return "Go"; }
    @Override public Icon getIcon() { return Icon.TOOLS; }

    @Override public List<BaseDomainMenuAction> getChildMenus() {
        return Arrays.asList(
            new BaseDomainMenuAction("Run go.mod", e -> {
                Platform.getProject().getTaskExecutor().execute("go-mod-tidy");
            }),
            new BaseDomainMenuAction("Open Gopath", e -> {
                Platform.getEditorManager().openFile(new File(System.getenv("GOPATH")));
            })
        );
    }
}

The domain.menu.editor.code extension point allows adding menus to the editor's code area (e.g., right-click to run a single test).


10. Settings Pages: platform.settingsBuilder Extension Point

Add a new settings page to the IDE settings dialog:

public class GoSettingsBuilder extends SettingsBuilder {
    @Override public String getName() { return "Go"; }
    @Override public Icon getIcon() { return Icon.SETTINGS; }

    @Override public View createView(LayoutInflater inflater, ViewGroup parent) {
        // Inflate your custom settings layout
        View view = inflater.inflate(R.layout.settings_go, parent, false);
        // Initialize UI components (edit texts, switches)
        return view;
    }

    @Override public void save() {
        // Save settings to SharedPreferences or project.json
    }
}

11. Packaging and Distribution: .rmx File Structure

A complete .rmx file is an APK with the following structure:

META-INF/
  program.json                   # Extension point declarations (required)
  MANIFEST.MF                    # Standard JAR manifest (optional)
  SIGN.RSA / SIGN.SF             # Signature (standard APK signing)
res/                             # Resources (icons, layouts, strings)
  drawable-xxxhdpi/
    plugin_icon.png
lib/
  arm64-v8a/
    libnative.so                 # Native libraries (if any)
classes.dex                      # Compiled plugin code
AndroidManifest.xml              # Minimal manifest (optional, can be empty)

Naming convention: File name should be com.yourdomain.pluginname_1.0.rmx. Place it in the plugins/ directory of Tiecode Studio on the device, or install it through the plugin market.


12. Summary of Common Patterns and Pitfalls

PatternExampleDescription
Reuse host compilerAAR pluginCall getDependencyTaskByName("compileWithTiecodec") instead of bundling your own compiler
Task dependenciesGo pluginpublishLib.dependsOn(buildLibmain) to ensure build order
Abort on failureGo pluginUse TaskInterruptError to abort the task chain, preventing the run configuration from executing
Environment setupGo pluginOs.setenv("GOROOT", ...) in Task.prepare()
LSP lifecycleGo pluginDestroy the LSP subprocess in AndroidPlugin.onUninstall()
Retroactive capabilitiesGo pluginWrite marker files in CodeProject.prepare() for existing projects
Prevent NPEAll tasksMust override prepare() and assign this.logger = logger, otherwise execute() will crash

Translator's note: The original Chinese skill contains a program.json snippet with "name": "go语言工程插件" and "vendor": { "name": "boboyr", ... }. While most code examples are in English, these few strings were translated to maintain consistency with the target locale. The project identifier sample.go was kept unchanged as per the instruction to preserve code and identifiers.

Related Skills