Version: 1.0.0 | Date: 2026-03-26 | Author: CTO Agent
.dpk는 The Universe 런처에서 사용하는 Dash 플러그인 배포 형식입니다.
ZIP 기반 컨테이너로, Skin(UI) + Skill(로직) + 메타데이터 + 서명을 하나의 파일로 패키징합니다.
APK가 아닌 .dpk를 사용하는 이유:
my-dash-1.0.0.dpk (ZIP)├── MANIFEST.yaml # DASH.md 5-Layer 프론트매터 (필수)
├── classes.dex # Skill 비즈니스 로직 — R8 최적화 DEX (필수)
├── skins/ # @Composable UI 코드 (필수)
│ └── SkinModule.jar # composable_entry 클래스 포함
├── res/ # 리소스 (선택)
│ └── drawable/
│ └── ic_dash.png
├── assets/ # 추가 에셋 (선택)
├── schemas/ # Protocol 메시지 스키마 (선택)
│ └── MyData.v1.json
├── signature.sig # EdDSA 코드 서명 (필수)
└── checksum.sha256 # 전체 파일 SHA-256 해시 (필수)
| 파일 | 설명 |
|------|------|
| MANIFEST.yaml | DASH-schema-v1.json 준수 5-Layer 정의 |
| classes.dex | Skill 클래스 (DashSkill 인터페이스 구현) |
| skins/ | 1개 이상의 @Composable JAR |
| signature.sig | EdDSA (Ed25519) 서명 |
| checksum.sha256 | 모든 파일의 SHA-256 해시 목록 |
DASH-schema-v1.json을 준수하는 YAML 파일. docs/specs/DASH-template.md 참조.
meta:id: com.example.my-dash
name: My Dash
version: 1.0.0
category: utility
keywords: [keyword1, keyword2]
author: developer@example.com
trigger:
conditions:
- type: always
skin:
sizes: [mini, standard]
theme_aware: true
composable_entry: MyDashSkin
skill:
entry: MyDashSkill
permissions: [network]
local_state: false
allowed_apis: [weather_api]
protocol:
publish: []
subscribe: []
fusible_with: []
imports: []
1. 개발자 키 생성 (Ed25519)
openssl genpkey -algorithm Ed25519 -out developer.key
openssl pkey -in developer.key -pubout -out developer.pub
2. 서명 대상: signature.sig 제외한 모든 파일의 SHA-256
find . -not -name 'signature.sig' -type f | sort | \
xargs sha256sum > checksum.sha256
3. EdDSA 서명
openssl pkeyutl -sign -inkey developer.key \
-in checksum.sha256 -out signature.sig
class DashSignatureVerifier(private val trustedPublicKeys: List) { fun verify(dpkFile: File): Boolean {
val zip = ZipFile(dpkFile)
val checksumEntry = zip.getEntry("checksum.sha256")
val signatureEntry = zip.getEntry("signature.sig")
val checksum = zip.getInputStream(checksumEntry).readBytes()
val signature = zip.getInputStream(signatureEntry).readBytes()
// Verify each file hash matches checksum.sha256
if (!verifyFileHashes(zip, checksum)) return false
// Verify EdDSA signature
return trustedPublicKeys.any { publicKey ->
val sig = Signature.getInstance("Ed25519")
sig.initVerify(publicKey)
sig.update(checksum)
sig.verify(signature)
}
}
}
The Universe Root CA (오프라인)└── Developer Signing CA (온라인)
└── 개발자 인증서 (개인키로 .dpk 서명)
1. 다운로드├── Dash Store CDN: GET /store/dashes/{id}/download → Signed URL
└── Play Store: Wrapper APK → assets/{name}.dpk 추출
├── checksum.sha256 파일별 해시 확인
└── signature.sig EdDSA 검증 (The Universe CA 체인)
├── MANIFEST.yaml 스키마 검증 (validate-dash.sh)
├── permissions 검토 (DANGEROUS 이상 → 사용자 확인)
└── DEX 바이트코드 기본 분석 (위험 API 호출 감지)
├── ZIP 해제 → files/dashes/installed/{dash_id}/
├── Dash Registry Room DB 등록
└── 라이프사이클: CREATED 상태
├── DexClassLoader로 classes.dex 로딩 (격리된 ClassLoader)
├── DashSkillContext 샌드박스 생성 (allowed_apis 강제)
├── @Composable 리플렉션 로딩 (composable_entry)
└── 라이프사이클: INITIALIZED → ACTIVE
files/dashes/installed/{dash_id}/
├── MANIFEST.yaml
├── classes.dex
├── skins/
├── res/
├── assets/
└── _meta/
├── installed_at.txt # ISO 8601 설치 일시
├── version.txt # 현재 설치 버전
└── signature_valid.txt # true/false
.dpk를 Play Store에서도 배포하기 위한 래퍼 APK 전략:
weather-dash-wrapper.apk├── AndroidManifest.xml
│
│
│
│
├── assets/
│ └── weather-dash-1.0.0.dpk
└── src/
└── InstallDashActivity.kt
// 1. .dpk를 런처에 전달 (ContentProvider 또는 FileProvider)
// 2. 런처가 설치 완료 확인
// 3. Wrapper APK 자기 삭제 (선택적)
사용자 플로우:
1. 프로젝트 생성
dash-cli create weather-dash
cd weather-dash/
2. 구조
ls
DASH.md # 5-Layer 정의
src/
WeatherDashSkin.kt # @Composable UI
WeatherDashSkill.kt # 비즈니스 로직
res/
drawable/ic_weather.png
3. 개발 (핫-리로드)
dash-cli dev # 런처에 실시간 연결
4. 검증
dash-cli validate # DASH.md 스키마 검증
dash-cli test # 단위 테스트 실행
5. 빌드
dash-cli build # → weather-dash-1.0.0.dpk 생성
6. 배포
dash-cli publish # Dash Store 업로드
dash-cli wrap # Play Store Wrapper APK 생성
{id}-{version}.dpk (예: weather-dash-1.0.0.dpk)val dashClassLoader = DexClassLoader(dexPath = installedDexPath,
optimizedDirectory = cacheDir,
librarySearchPath = null, // 네이티브 라이브러리 차단
parent = dashSdkClassLoader // Dash SDK 인터페이스만 노출
)
files/dashes/installed/{dash_id}/ 범위로 제한신뢰도가 낮은 Dash는 별도 프로세스에서 실행:
android:name=".DashSkillService" android:process=":dash_sandbox"
android:isolatedProcess="true" />
data class ResourceQuota(val memoryMb: Int = 32, // 4~256MB
val networkKbPerMin: Int = 512, // 0~10240 KB/min
val cpuPercent: Int = 10 // 1~50%
)
Orchestrator가 실시간 모니터링, 초과 시 Dash 일시정지 또는 종료.
docs/specs/DASH-schema-v1.json — 5-Layer JSON Schemadocs/specs/DASH-template.md — DASH.md 공식 템플릿docs/specs/versioning-policy.md — 스키마 버전 정책docs/specs/sample-dashes/weather-dash.md — Weather Dash 샘플docs/research/security-sandbox-research.md — 보안 샌드박스 리서치docs/research/runtime-plugin-research.md — 런타임 플러그인 리서치