结绳插件开发
「结绳 IDE / QiStudio」(호스트 패키지명
com.tiecode.develop)를 위한 플러그인 개발 문서입니다. 「结绳 Studio」의 공식 명칭은 QiStudio(차세대 개방형 엔지니어링 플랫폼, 모바일 최초 OSGi 표준 구현 앱, 「마이크로 컴포넌트/플러그인」 형태로 엔지니어링 개발 환경 확장)입니다. 내용 출처:studio-api-1.0-preview5.jar(com.rapid.api.*)역컴파일 + go / scala / kotlin / linux / aar / libgdx / 설치 없이 실행 등 10여 개 실제 플러그인의 소스 코드 복원.
공식 자료 및 저장소(중요)
공식 Gitee 저장소
| 저장소 | 설명 |
|---|---|
| MobileIPE-Plugin-DevManual | 공식 플러그인 개발 튜토리얼(QiStudio 마이크로 컴포넌트). QiStudio核心体系介绍.md, Rapid框架介绍.md, plugin/扩展点介绍.md, plugin/插件清单配置.md, plugin/注册你的微组件——插件.md 포함 |
| TiecodeCompiler-Public | 结绳 컴파일러(크로스 플랫폼 버전)산출물 배포 저장소. docs/(컴파일러 사용/문법/패키징/플랫폼 통합 문서), headers/tiec/(C API + C++ 패키징 헤더 파일), prebuilt/(cli + android/windows/linux/ohos/wasm 동적 라이브러리), stdlibs/(안드로이드/CXX/웹 기본 라이브러리) 포함 |
| QiStudio-PluginSamples | 공식 플러그인 샘플 프로젝트 모음(19+개 예제: 의존성 주입, 편집기 효과/레인보우 브래킷, 플로팅 로그, Html 프로젝트 관리자, 네트워크 요청, 아이콘 확장, Javac9 도구 체인, 언어 하이라이팅, 사용자 정의 테마, Application 생명주기, 프로젝트 컴포넌트, 각종 메뉴, 도구 페이지, 설정 페이지 등) |
공식 API jar 파일명은
qistudio-api-<버전>.jar입니다(이 스킬에서 역컴파일한studio-api-1.0-preview5.jar는 호스트 측 SDK입니다). QQ 교류 그룹: 1016399857.
커뮤니티 참고 구현(GitHub)
이 스킬과 함께 제공되는 실제 플러그인 소스 코드 모음(단일 저장소, 여러 디렉토리, 8개의 완전 컴파일 가능 플러그인 포함):
https://github.com/boboyr/tiecode-plugin
| 디렉토리 | 플러그인 | 시연 기능 |
|---|---|---|
go语言工程插件/ | go 언어 엔지니어링(콘솔+SDL3) | 이중 템플릿 + LSP(gopls) 자동 완성 + TextMate 하이라이팅 + 도구 체인 + 실행 구성 + 파일 트리 가상 노드 |
结绳安卓工程aar构建插件/ | aar/jar 빌드 | 호스트 컴파일 체인 재사용 + NameGenerator 한글 출력 |
结绳免安装运行插件/ | 설치 없이 실행기 | 호스트 태스크 재사용 + 플러그인 방식으로 미설치 APK 로딩 |
libgdx游戏编辑器插件/ | libgdx 비주얼 에디터 | 디자이너 + 편집기 코드 영역 메뉴 + 새 장면 클래스 |
scala安卓工程插件/ | Scala 안드로이드 엔지니어링 | 완전한 sbt 빌드 체인 + 「结绳 플러그인 프로젝트」 템플릿 + 빌드/디버그 플러그인 |
结绳Linux工程插件/ | 结绳 Linux-SDL3 | GCC 도구 체인 + SDL3 + 태스크 체인 |
外部kotlin文件注解插件/ | 외부 Kotlin 파일 어노테이션 | 结绳 컴파일러 API: CompilerPlugin + AnnotationProcessor + Kotlin 자동 완성 |
BasicLanguages-lang参考/ | 공식 기본 언어 | csml/json/markdown/xml/properties 언어 하이라이팅 참고 |
0. 핵심 개념 및 전체 아키텍처
结绳은 모듈식 IDE 호스트이며, 플러그인은 .rmx 파일로 배포됩니다. 하나의 .rmx는 본질적으로 APK입니다: AndroidManifest.xml + classes.dex + META-INF/program.json. 호스트는 manifest의 <application> 또는 4대 컴포넌트가 아닌, program.json의 확장 포인트(extension point) 선언을 통해 플러그인 기능을 발견합니다.
0.1 세 가지 핵심 패키지
| 패키지 | 역할 |
|---|---|
com.rapid.api.* | 플러그인 SDK(本次文档主体). 프로젝트, 언어, 태스크, 구조, 페이지, UI, 네트워크 등 |
com.rapid.framework.* | 프레임워크 계층: VFS(가상 파일 시스템), Service/Data/Event Keys, program/plugin 컨테이너 |
com.tiecode.compiler.* | 结绳 컴파일러(구문 트리 / 심볼 테이블 / 도구 체인 completer/processor)——호스트 측, 플러그인은 일반적으로 toolchain 하위 패키지만 사용 |
0.2 확장 포인트(program.json의 extension 배열)
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 필드 설명(호스트 최소 지원 버전)
minSupport는 정수로, 플러그인이 요구하는 호스트 结绳의 최소 버전을 나타냅니다. 버전에 따라 값이 다릅니다:
| 结绳 버전 | minSupport | 설명 |
|---|---|---|
| 结绳 4.6 | 1 | 4.6 플러그인은 "minSupport": 1로 작성 |
| 结绳 4.7 | 2 | 4.7 플러그인은 "minSupport": 2로 작성 |
즉, 4.6용 플러그인 개발 시
minSupport는1을 입력하고, 4.7로 업그레이드하거나 4.7 대상 플러그인은2를 입력합니다. 값과 호스트 버전 간의 구체적인 바인딩 규칙은 공식 기준을 따르며, 개발 시 대상 호스트 버전에 맞춰 작성하면 됩니다.
확인된 확장 포인트全集(point 필드):
| 확장 포인트 | 클래스 구현/상속 | 역할 | 출처 플러그인 |
|---|---|---|---|
application | AndroidPlugin | 플러그인 진입점, onInit/activate/onUninstall | go/scala/aar/설치 없음 |
project.manager | ProjectManager(주로 CodeProjectManager 사용) | 프로젝트 유형 등록 | go/scala/linux |
project.language | LanguageFactory | 언어 등록(하이라이팅 + 연관 파일 확장자), scope 가능 | go/scala |
project.language.engine | LanguageEngine | 언어 엔진 등록(자동 완성/진단 등 provider 컨테이너) | 结绳 콘솔 플러그인 |
project.toolchain | Tool 하위 클래스(예: SunJdk8Compiler) | 컴파일 도구 체인 등록 | JavaCompiler8 |
project.component | ComponentIntegrator/ComponentFactory | 프로젝트 열 때 컴포넌트 마운트(실행 구성/최초 팝업/hook) | linux/kotlin/aar/설치 없음 |
project.file.creationOption | PSObjectCreationOption | 파일 트리 「새 파일」 메뉴 항목 | kotlin/libgdx |
project.file.openWithEditor | PSObjectOpeningOption | 파일 「열기 방식」 | kotlin |
project.event.fileUi | ProjectFileUiEvent | 파일 트리 UI 이벤트(아이콘 바인딩 등) | kotlin |
domain.menu | BaseDomainMenuAction/메뉴 action | 최상위 메뉴 항목 | go |
domain.menu.editor.code | 편집기 코드 영역 메뉴 | libgdx | |
platform.settingsBuilder | SettingsBuilder | 설정 페이지에 하위 페이지 추가 | scala 안드로이드 |
project.file.creationOption | — | — | — |
참고:
scope.identifiers는 언어/컴포넌트를 특정 프로젝트 typeId(예:sample.go)로 제한하는 데 사용됩니다. 일부 확장 포인트의 class는None(플레이스홀더)일 수 있습니다.
1. 플러그인 진입점: application 확장 포인트
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) {
// 사용자 정의 컴파일 도구 체인 등록(예: go 컴파일러)
ToolchainService service = Platform.getService(ProjectServiceKeys.TOOLCHAIN);
service.setTool(GoCompileApiKeys.Gocompile, new BaseGoCompiler());
}
@Override
public void activate() {
// 플러그인이 활성화될 때 한 번 실행(주로 hook, 리스너, 컴파일 플러그인 장착)
}
@Override
public void onUninstall() {
// 제거 정리: 자신이 실행한 하위 프로세스 종료(예: gopls), LSP 연결 해제
}
}
핵심 API(com.rapid.api.Platform):
Platform.getService(Key<T>)—— 호스트 서비스 가져오기(예:ProjectServiceKeys.TOOLCHAIN)Platform.getProject()—— 현재 열려 있는 프로젝트 객체Platform.getApplicationContext()—— 호스트 Context
2. 프로젝트 유형: project.manager 확장 포인트
플러그인은 ProjectManager를 통해 하나의 「프로젝트 유형」(예: go语言工程, 结绳安卓工程)을 등록합니다.
2.1 관리자 뼈대
public class GoProjectManager extends CodeProjectManager<GoProject> {
public final static String TYPE = "go语言工程"; // 표시 이름
public final static String IDENTIFIER = "sample.go"; // typeId, project.json에 저장됨
public GoProjectManager() {
super();
this.fileManager = new GoFileManager(); // 선택 사항: 사용자 정의 파일 관리자(아이콘 바인딩 등)
// ① 파일 열기 방식(확장자별)
fileManager.addPSObjectOpeningOption(DefaultOpeningOption.INSTANCE, ".go", ".mod");
// ② 파일 트리 노드 확장 방식(가상 「외부 라이브러리」 노드)
fileManager.addPSObjectExpansionCase(new ExternalLibrariesExpansionCase(), MARKER);
// ③ 새 파일 메뉴 항목
fileManager.addPSObjectCreationOption(new GoFileCreationOption());
// ④ 언어 엔진 및 언어 팩토리
languageManager.registerEngine("go", GoLanguageEngine.getInstance());
languageManager.registerLanguageFactory(new GoLanguageFactory());
languageManager.registerOperatorProvider(GoLanguage.ID, new GoOperatorProvider());
// ⑤ 프로젝트 생성 템플릿
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 인터페이스 메서드(javap 출처):
String getIdentifier();
TypeDescription getTypeDescription(); // 이름 + 유형 + 아이콘
List<Template<T>> getTemplates();
void addTemplate(Template<T>);
ProjectFileManager<T> getFileManager();
T newProject();
void load(T, LoadingPresentation);
boolean isProjectDir(File); // 특정 디렉토리가 해당 유형의 프로젝트인지 판단
String backup(T); void delete(T);
TypeDescription의 유형 상수: APPLICATION / CONSOLE / LIBRARY.
3. 프로젝트 객체 및 파이프라인 조립: CodeProject.prepare()
프로젝트 유형은 Project 하위 클래스에 해당합니다. prepare()는 프로젝트를 열 때 호스트에 의해 호출되며, 이 시점에 템플릿 파일이 이미 생성되어 있으므로 디렉토리 내용을 기반으로 태스크 체인, 실행 구성, 컴포넌트를 조립할 수 있습니다.
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); // 태스크 의존성
addRunConfiguration(new GoSdl3RunConfiguration());
} else {
addTask(new CompilerGoTask());
addTask(new RunGoTask());
addRunConfiguration(new GoStartRunConfig());
addRunConfiguration(new ElfRunConfig());
}
}
@Override public ProjectVariant getVariant() { return ProjectVariant.DEBUG; }
}
CodeProject(BaseProject 확장)핵심 메서드:
void prepare();
TaskContainer getTasks(); TaskExecutor getTaskExecutor();
void addTask(Task); void setTasks(Iterable<Task>);
void addRunConfiguration(RunConfiguration); // CodeProject 고유
ProjectVariant getVariant(); void setVariant(ProjectVariant);
Logger getLogger(); void setLogger(Logger);
String getName();
File getProjectDir(); File getChildFile(String); // 프로젝트 상대 경로를 File로 변환
void recycle();
ProjectVariant 값: DEBUG / RELEASE / UNDEFINED.
팁(go 플러그인 출처):
prepare()에서 프로젝트에 마커 파일(예:External Libraries)을 추가로 작성하면, 이미 존재하는 기존 프로젝트에 한 번에 기능을 추가할 수 있어 프로젝트를 다시 생성할 필요가 없습니다.
4. 프로젝트 템플릿: BaseTemplate
템플릿은 「새 프로젝트」 대화상자에서 어떤 옵션을 선택할 수 있는지, 생성 시 어떤 파일을 작성할지 결정합니다.
public class GoConsoleTemplate extends BaseTemplate<GoProject> {
@Override public String getName() { return "콘솔 프로젝트"; }
@Override public Drawable getPicture() { return null; } // 템플릿 미리보기 이미지, null 가능
@Override public String getDefaultProjectName() { return "내 go 콘솔 프로젝트"; }
@Override public Form getForm() { return new Form(); } // 입력 항목 추가 가능
@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); // 프로젝트 디렉토리에 쓰기
FileUtils.writeFile("module main\ngo 1.26.0", project.getChildFile("src/go.mod"));
listener.onSuccess(); // 성공 콜백
} catch (IOException e) {
listener.onFail("기본 파일 쓰기 실패"); // 실패 콜백
}
}
}
Template<T> 인터페이스 메서드:
String getName();
Drawable getPicture();
String getDefaultProjectName();
Form getForm(); // com.rapid.framework.data.form.Form, addInput(new FormInput(...)) 가능
void create(T, Form, OnProjectCreateListener); // OnProjectCreateListener.onSuccess()/onFail(msg)
템플릿 리소스 포함: 템플릿 파일을 app/src/main/assets/<name>에 넣고,
AssetUtils.readAsset / AssetUtils.unZipAssetsFolder(context, zipName, destDir)을 사용하여 읽고 압축을 풉니다.
(SDL3 프로젝트 템플릿은 asset의 gosdl3_template.zip 전체를 프로젝트 디렉토리에 압축 해제하는 방식 사용)
5. 컴파일 태스크 및 도구 체인: BaseTask + ToolchainService
5.1 태스크 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("도구 체인 설치 중..."); 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());
}
// 반드시 재정의: 기본 BaseTask.prepare는 UnsupportedOperationException을 던짐;
// 또한 logger/variant 필드를 여기서 할당하지 않으면 execute()에서 logger.info 호출 시 NPE 발생.
@Override public void prepare(Project project, ProjectVariant variant, Logger logger) {
this.logger = logger;
this.variant = variant;
Os.setenv("GOROOT", goRoot, false); // 환경 변수 설정(android.system.Os)
}
@Override public String getId() { return "compileWithGo"; } // 실행 구성 getTaskId()에서 참조 용도
@Override public String getName() { return "대상 플랫폼으로 컴파일"; }
}
Task 인터페이스(javap 출처):
String getId(); String getName();
void prepare(Project, ProjectVariant, Logger); // 기본 예외 발생하므로 반드시 재정의
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();
주의사항 (go 플러그인 주석 원문): 태스크에서
logger를 할당하지 않으면,execute()에서logger.info사용 시 NPE로 직접 실패하여 도구 체인 설치가 절대 실행되지 않습니다.
5.2 도구 체인 Tool + Installable
public interface Tool { /* ANDROID_SDK/AAPT/AAPT2/D8/R8/DX/PROGUARD/
MANIFEST_MERGER/APK_SIGNER/JAVA_SDK/JAVA_COMPILER 등 Key 내장 */ }
public interface Installable {
boolean isInstalled(Context);
void install(Context) throws IOException;
}
- 사용자 정의 도구 체인은
application.onInit()에서ToolchainService.setTool(customKey, impl)로 등록합니다. - 내장 Android 도구 체인 Key는 모두
Tool인터페이스에 있습니다(직접Platform.getService(TOOLCHAIN).getTool(Tool.AAPT2)등으로 사용 가능). - 호스트 컴파일 체인 재사용(aar 플러그인 / 설치 없이 실행 플러그인 방식): 자체 컴파일러를 패키징하지 않고,
getDependencyTaskByName("compileWithTiecodec")등으로 호스트 태스크를 가져와 의존성을 걸거나,getTaskId()를 직접 재사용합니다.
6. 실행 구성: RunConfiguration / TaskRunConfiguration
프로젝트의 「실행」 메뉴에 실행 가능한 항목을 추가합니다. 가장 일반적인 것은 TaskRunConfiguration: 태스크 id를 지정하고,
태스크 실행 성공 시 onResult 콜백을 호출합니다.
public class GoStartRunConfig extends TaskRunConfiguration {
public Project getProject() { return Platform.getProject(); }
public String getTaskId() { return "RunWithGo"; } // 연결된 태스크 id
public ProjectVariant getVariant() { return ProjectVariant.DEBUG; }
public Icon getIcon() { return GoIcons.RUN; }
public String getDisplayName() { return "Go 프로그램 실행"; }
@Override
public void result(RunConfiguration.Result result) {
if (result.isSuccess()) {
logger.info("실행 성공: " + result.getMessage());
} else {
logger.error("실행 실패: " + result.getMessage());
}
}
@Override
public void onResult(RunConfiguration.Result result) { result(result); }
}
7. 언어 엔진: LanguageEngine + LanguageFactory
LanguageEngine은 언어와 관련된 모든 Provider를 담는 컨테이너입니다. project.language.engine 확장 포인트를 통해 등록하거나,
ProjectFileManager에서 registerEngine을 통해 등록합니다.
주요 Provider 인터페이스:
DocumentProvider: 문서 포맷(주석/들여쓰기/괄호 매칭 등)CompletionProvider: 코드 자동 완성(TextMate/LSP/Keyword 등 여러 출처 지원)DiagnosticProvider: 구문 검사 및 진단HoverProvider: 마우스 호버 시 정보 표시NavigationProvider: 정의로 이동 / 참조 찾기SignatureProvider: 메서드 시그니처 힌트
LanguageFactory는 언어의 기본 정보(id, 표시 이름, 파일 확장자)와 LanguageEngine을 연결합니다.
8. 파일 트리 사용자 정의: PSObject 계열
8.1 가상 노드:
PSObjectExpansionCase는 가상 노드(예: 「외부 라이브러리」 폴더)를 동적으로 표시하는 데 사용됩니다.
public class ExternalLibrariesExpansionCase extends PSObjectExpansionCase {
@Override
public boolean isExpansionCase(Object marker) {
return MARKER.equals(marker); // ProjectFileManager.addPSObjectExpansionCase에서 전달한 marker
}
@Override
public List<PSObject> computeChildren(PSObject parent) {
List<PSObject> children = new ArrayList<>();
children.add(new ExternalLibraryNode("go 표준 라이브러리", "/usr/local/go/src"));
return children;
}
}
8.2 새 파일 생성:
PSObjectCreationOption은 파일 트리 우클릭 메뉴의 「새 파일」 항목을 정의합니다.
public class GoFileCreationOption extends PSObjectCreationOption {
@Override public String getName() { return "Go 파일"; }
@Override public Drawable getIcon() { return GoIcons.FILE; }
@Override public boolean isAvailable(PSObject parent) { return true; }
@Override
public void onCreate(PSObject parent, String name, Consumer<String> onFinish) {
// 파일 생성 로직
String content = "package main\n\nfunc main() {\n\tprintln(\"Hello, Go!\")\n}\n";
// 파일 시스템에 쓰기
onFinish.accept(name + ".go"); // 생성 완료 콜백
}
}
8.3 파일 열기 방식:
PSObjectOpeningOption은 특정 파일에 대한 사용자 정의 열기 방식을 등록합니다.
9. 메뉴: BaseDomainMenuAction
domain.menu 확장 포인트를 사용하여 IDE 상단 메뉴에 새 항목을 추가하거나 드롭다운 메뉴를 확장합니다.
public class GomodMenu extends BaseDomainMenuAction {
@Override public String getText() { return "Go 모듈"; }
@Override public Drawable getIcon() { return GoIcons.MODULE; }
@Override
public void actionPerformed(ActionEvent e) {
// 메뉴 클릭 처리
Platform.getProject().getTasks().executeTask("goModTidy", new TaskCallback() {
@Override public void onSuccess() { /* 성공 처리 */ }
@Override public void onFailure(String msg) { /* 실패 처리 */ }
});
}
}
또한 domain.menu.editor.code 확장 포인트를 사용하여 코드 편집기 영역에 우클릭 메뉴를 추가할 수 있습니다(libgdx 플러그인 참조).
10. 설정 페이지: SettingsBuilder
platform.settingsBuilder 확장 포인트를 사용하여 플러그인 고유의 설정 페이지를 추가합니다.
public class GoSettingsBuilder implements SettingsBuilder {
@Override public String getTitle() { return "Go"; }
@Override public Drawable getIcon() { return GoIcons.SETTINGS; }
@Override
public SettingsPage build() {
// Android 표준 PreferenceScreen 또는 사용자 정의 레이아웃 반환
return new GoSettingsPage();
}
}
11. 결绳 컴파일러 API: CompilerPlugin + AnnotationProcessor
외부 Kotlin 파일 플러그인은 결绳 컴파일러 플러그인 시스템을 시연합니다:
CompilerPlugin: 컴파일러 수명주기(컴파일 전/후 처리)에 연결AnnotationProcessor: 컴파일 중 어노테이션을 처리하여 추가 코드 생성- 결绳 코드 완성 엔진과 결합하여 Kotlin에 대한 자동 완성 제공
상세 내용은
externalKotlinFileAnnotationPlugin/소스 코드 참조.
12. .rmx 패키징 및 배포
.rmx는 다음을 포함하는 Android APK입니다:
AndroidManifest.xml(플러그인 메타데이터)classes.dex(컴파일된 Java/Kotlin 코드)META-INF/program.json(확장 포인트 선언, 필수)
패키징 단계:
- Android Studio 또는 Gradle을 사용하여 APK 빌드
- 서명된 APK의 확장자를
.rmx로 변경 - 사용자가结绳 IDE에서 직접 열거나 설치
13. 추가 팁 및 주의사항
- 로거 NPE 문제:
BaseTask.prepare()에서this.logger를 반드시 할당하십시오. - 환경 변수: 안드로이드 환경에서
android.system.Os.setenv()를 사용하여 PATH 및 GOROOT 등을 설정하십시오. - 리소스 관리:
AssetUtils.readAsset()및AssetUtils.unZipAssetsFolder()를 사용하여 플러그인 asset에서 템플릿 파일을 읽고 압축 해제하십시오. - 호환성:
program.json의minSupport버전을 확인하여 플러그인이 올바른结绳 버전을 대상으로 하는지 확인하십시오. - 디버깅: 결绳의 로컬 로그 도구를 사용하여
System.out.println()출력, logcat 또는 특수하게 연결된 플러그인 로그를 확인하십시오.
이 스킬은 계속 업데이트됩니다. 모든 내용은 Gitee의 공식 문서와 GitHub의 커뮤니티 예제를 참조합니다. 질문이나 기여는 GitHub 저장소를 통해 Issue를 제출해 주십시오.