@simplysm/capacitor-plugin-intent 12.16.52 → 14.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -139
- package/android/build.gradle +1 -0
- package/android/src/main/kotlin/kr/co/simplysm/capacitor/intent/IntentPlugin.kt +365 -0
- package/dist/Intent.d.ts +29 -18
- package/dist/Intent.d.ts.map +1 -0
- package/dist/Intent.js +41 -22
- package/dist/Intent.js.map +1 -0
- package/dist/IntentPlugin.d.ts +72 -0
- package/dist/IntentPlugin.d.ts.map +1 -0
- package/dist/IntentPlugin.js +2 -0
- package/dist/IntentPlugin.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -0
- package/dist/web/IntentWeb.d.ts +7 -5
- package/dist/web/IntentWeb.d.ts.map +1 -0
- package/dist/web/IntentWeb.js +17 -13
- package/dist/web/IntentWeb.js.map +1 -0
- package/package.json +15 -10
- package/src/Intent.ts +56 -25
- package/src/IntentPlugin.ts +81 -0
- package/src/index.ts +2 -1
- package/src/web/IntentWeb.ts +27 -16
- package/android/src/main/java/kr/co/simplysm/capacitor/intent/IntentPlugin.java +0 -376
- package/dist/IIntentPlugin.d.ts +0 -63
- package/dist/IIntentPlugin.js +0 -1
- package/src/IIntentPlugin.ts +0 -65
- package/tests/slice1-directory-and-config.spec.ts +0 -50
- package/tests/slice2-java-renaming.spec.ts +0 -34
- package/tests/slice3-typescript-renaming.spec.ts +0 -76
- package/tests/slice4-docs-and-deprecation.spec.ts +0 -31
- package/tests/slice5-start-activity-for-result-android.spec.md +0 -98
- package/tests/slice5-start-activity-for-result-types.spec.ts +0 -40
- package/tests/slice6-start-activity-for-result-web.spec.ts +0 -34
- package/tsconfig.json +0 -8
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "fs";
|
|
2
|
-
import { resolve } from "path";
|
|
3
|
-
|
|
4
|
-
const pkgRoot = resolve(import.meta.dirname, "..");
|
|
5
|
-
const srcDir = resolve(pkgRoot, "src");
|
|
6
|
-
|
|
7
|
-
describe("Slice 3: TypeScript 소스 리네이밍", () => {
|
|
8
|
-
// Scenario: 메인 클래스 파일 및 클래스명 변경
|
|
9
|
-
test("Intent.ts에 abstract class Intent가 존재한다", () => {
|
|
10
|
-
expect(existsSync(resolve(srcDir, "Intent.ts"))).toBe(true);
|
|
11
|
-
const content = readFileSync(resolve(srcDir, "Intent.ts"), "utf-8");
|
|
12
|
-
expect(content).toContain("abstract class Intent");
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
test('registerPlugin<IIntentPlugin>("Intent", ...) 호출이 존재한다', () => {
|
|
16
|
-
const content = readFileSync(resolve(srcDir, "Intent.ts"), "utf-8");
|
|
17
|
-
expect(content).toContain('registerPlugin<IIntentPlugin>("Intent"');
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
// Scenario: 플러그인 인터페이스 파일 및 타입명 변경
|
|
21
|
-
test("IIntentPlugin.ts에 IIntentPlugin, IIntentResult 인터페이스가 존재한다", () => {
|
|
22
|
-
expect(existsSync(resolve(srcDir, "IIntentPlugin.ts"))).toBe(true);
|
|
23
|
-
const content = readFileSync(resolve(srcDir, "IIntentPlugin.ts"), "utf-8");
|
|
24
|
-
expect(content).toContain("interface IIntentPlugin");
|
|
25
|
-
expect(content).toContain("interface IIntentResult");
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// Scenario: Web stub 파일 및 클래스명 변경
|
|
29
|
-
test("IntentWeb.ts에 class IntentWeb extends WebPlugin implements IIntentPlugin이 존재한다", () => {
|
|
30
|
-
expect(existsSync(resolve(srcDir, "web/IntentWeb.ts"))).toBe(true);
|
|
31
|
-
const content = readFileSync(resolve(srcDir, "web/IntentWeb.ts"), "utf-8");
|
|
32
|
-
expect(content).toContain("class IntentWeb extends WebPlugin implements IIntentPlugin");
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// Scenario: index.ts export 경로 갱신
|
|
36
|
-
test('index.ts에 export * from "./Intent"와 export * from "./IIntentPlugin"이 존재한다', () => {
|
|
37
|
-
const content = readFileSync(resolve(srcDir, "index.ts"), "utf-8");
|
|
38
|
-
expect(content).toContain('export * from "./Intent"');
|
|
39
|
-
expect(content).toContain('export * from "./IIntentPlugin"');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
// Scenario: subscribe API 보존
|
|
43
|
-
test("Intent.subscribe API가 존재하고 함수를 반환한다", async () => {
|
|
44
|
-
const mod = await import(resolve(srcDir, "Intent.ts"));
|
|
45
|
-
expect(typeof mod.Intent.subscribe).toBe("function");
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
// Scenario: send API 보존
|
|
49
|
-
test("Intent.send API가 존재한다", async () => {
|
|
50
|
-
const mod = await import(resolve(srcDir, "Intent.ts"));
|
|
51
|
-
expect(typeof mod.Intent.send).toBe("function");
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// Scenario: getLaunchIntent API 보존
|
|
55
|
-
test("Intent.getLaunchIntent API가 존재한다", async () => {
|
|
56
|
-
const mod = await import(resolve(srcDir, "Intent.ts"));
|
|
57
|
-
expect(typeof mod.Intent.getLaunchIntent).toBe("function");
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// Scenario: unsubscribeAll API 보존
|
|
61
|
-
test("Intent.unsubscribeAll API가 존재한다", async () => {
|
|
62
|
-
const mod = await import(resolve(srcDir, "Intent.ts"));
|
|
63
|
-
expect(typeof mod.Intent.unsubscribeAll).toBe("function");
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// Scenario: Web 환경에서 stub 동작
|
|
67
|
-
test("IntentWeb이 IIntentPlugin의 모든 메서드를 구현한다", async () => {
|
|
68
|
-
const mod = await import(resolve(srcDir, "web/IntentWeb.ts"));
|
|
69
|
-
const web = new mod.IntentWeb();
|
|
70
|
-
expect(typeof web.subscribe).toBe("function");
|
|
71
|
-
expect(typeof web.unsubscribe).toBe("function");
|
|
72
|
-
expect(typeof web.unsubscribeAll).toBe("function");
|
|
73
|
-
expect(typeof web.send).toBe("function");
|
|
74
|
-
expect(typeof web.getLaunchIntent).toBe("function");
|
|
75
|
-
});
|
|
76
|
-
});
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "fs";
|
|
2
|
-
import { resolve } from "path";
|
|
3
|
-
|
|
4
|
-
const pkgRoot = resolve(import.meta.dirname, "..");
|
|
5
|
-
const monoRoot = resolve(pkgRoot, "../..");
|
|
6
|
-
|
|
7
|
-
describe("Slice 4: 문서 갱신 및 npm deprecated", () => {
|
|
8
|
-
// Scenario: 패키지 README 갱신
|
|
9
|
-
test("패키지 README.md에 @simplysm/capacitor-plugin-intent 설치 안내가 있다", () => {
|
|
10
|
-
const readme = readFileSync(resolve(pkgRoot, "README.md"), "utf-8");
|
|
11
|
-
expect(readme).toContain("@simplysm/capacitor-plugin-intent");
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
test("패키지 README.md에 broadcast/Broadcast 문자열이 존재하지 않는다", () => {
|
|
15
|
-
const readme = readFileSync(resolve(pkgRoot, "README.md"), "utf-8");
|
|
16
|
-
// BroadcastReceiver는 Android API 용어이므로 제외하지 않음 — 여기서는 플러그인 이름 참조만 검사
|
|
17
|
-
expect(readme).not.toMatch(/capacitor-plugin-broadcast/);
|
|
18
|
-
expect(readme).not.toMatch(/\bBroadcast\b/);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
// Scenario: 루트 README 갱신
|
|
22
|
-
test("루트 README.md에 capacitor-plugin-intent 항목이 존재한다", () => {
|
|
23
|
-
const readme = readFileSync(resolve(monoRoot, "README.md"), "utf-8");
|
|
24
|
-
expect(readme).toContain("capacitor-plugin-intent");
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test("루트 README.md에 capacitor-plugin-broadcast 항목은 존재하지 않는다", () => {
|
|
28
|
-
const readme = readFileSync(resolve(monoRoot, "README.md"), "utf-8");
|
|
29
|
-
expect(readme).not.toContain("capacitor-plugin-broadcast");
|
|
30
|
-
});
|
|
31
|
-
});
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
# Slice 1: startActivityForResult Android 수동 테스트
|
|
2
|
-
|
|
3
|
-
## 전제 조건
|
|
4
|
-
|
|
5
|
-
- Capacitor 앱이 Android 디바이스/에뮬레이터에서 실행 중이다
|
|
6
|
-
- `capacitor-plugin-intent`가 플러그인으로 등록되어 있다
|
|
7
|
-
|
|
8
|
-
## Scenario: action만 지정하여 Activity 시작
|
|
9
|
-
|
|
10
|
-
### 수행 절차
|
|
11
|
-
1. `Intent.startActivityForResult({ action: "android.intent.action.PICK" })` 호출
|
|
12
|
-
2. Android 시스템이 해당 action을 처리할 수 있는 앱 목록을 표시하는지 확인
|
|
13
|
-
|
|
14
|
-
### 기대 결과
|
|
15
|
-
- 해당 action을 처리하는 Activity가 열린다
|
|
16
|
-
|
|
17
|
-
## Scenario: action + uri 지정
|
|
18
|
-
|
|
19
|
-
### 수행 절차
|
|
20
|
-
1. `Intent.startActivityForResult({ action: "android.intent.action.VIEW", uri: "content://contacts/people/1" })` 호출
|
|
21
|
-
|
|
22
|
-
### 기대 결과
|
|
23
|
-
- Intent의 data에 해당 URI가 설정되어 Activity가 열린다
|
|
24
|
-
|
|
25
|
-
## Scenario: extras 지정
|
|
26
|
-
|
|
27
|
-
### 수행 절차
|
|
28
|
-
1. `Intent.startActivityForResult({ action: "com.example.ACTION", extras: { "key": "value" } })` 호출
|
|
29
|
-
|
|
30
|
-
### 기대 결과
|
|
31
|
-
- Intent의 extra에 해당 데이터가 포함되어 Activity가 열린다
|
|
32
|
-
|
|
33
|
-
## Scenario: package + component로 명시적 Activity 지정
|
|
34
|
-
|
|
35
|
-
### 수행 절차
|
|
36
|
-
1. 대상 앱의 패키지명과 Activity 클래스명을 확인
|
|
37
|
-
2. `Intent.startActivityForResult({ action: "android.intent.action.MAIN", package: "com.example.app", component: "com.example.app.MainActivity" })` 호출
|
|
38
|
-
|
|
39
|
-
### 기대 결과
|
|
40
|
-
- 지정된 패키지의 지정된 Activity가 직접 열린다
|
|
41
|
-
|
|
42
|
-
## Scenario: type(MIME type) 지정
|
|
43
|
-
|
|
44
|
-
### 수행 절차
|
|
45
|
-
1. `Intent.startActivityForResult({ action: "android.intent.action.GET_CONTENT", type: "image/*" })` 호출
|
|
46
|
-
|
|
47
|
-
### 기대 결과
|
|
48
|
-
- Intent의 MIME type이 설정되어 이미지 선택 Activity가 열린다
|
|
49
|
-
|
|
50
|
-
## Scenario: uri + type 동시 지정
|
|
51
|
-
|
|
52
|
-
### 수행 절차
|
|
53
|
-
1. `Intent.startActivityForResult({ action: "android.intent.action.VIEW", uri: "content://media/images", type: "image/png" })` 호출
|
|
54
|
-
|
|
55
|
-
### 기대 결과
|
|
56
|
-
- Intent에 setDataAndType으로 URI와 MIME type이 함께 설정된다
|
|
57
|
-
|
|
58
|
-
## Scenario: 대상 Activity가 RESULT_OK로 종료
|
|
59
|
-
|
|
60
|
-
### 수행 절차
|
|
61
|
-
1. `Intent.startActivityForResult({ action: "android.intent.action.GET_CONTENT", type: "image/*" })` 호출
|
|
62
|
-
2. 열린 Activity에서 이미지를 선택
|
|
63
|
-
|
|
64
|
-
### 기대 결과
|
|
65
|
-
- Promise가 resolve되고 `{ resultCode: -1, data: "content://...", extras: {...} }` 형태의 결과를 반환한다
|
|
66
|
-
|
|
67
|
-
## Scenario: 대상 Activity가 RESULT_CANCELED로 종료 (사용자 뒤로가기)
|
|
68
|
-
|
|
69
|
-
### 수행 절차
|
|
70
|
-
1. `Intent.startActivityForResult({ action: "android.intent.action.GET_CONTENT", type: "image/*" })` 호출
|
|
71
|
-
2. 열린 Activity에서 뒤로가기 버튼 누름
|
|
72
|
-
|
|
73
|
-
### 기대 결과
|
|
74
|
-
- Promise가 resolve되고 `{ resultCode: 0 }`을 반환한다
|
|
75
|
-
|
|
76
|
-
## Scenario: 대상 Activity가 data 없이 종료
|
|
77
|
-
|
|
78
|
-
### 수행 절차
|
|
79
|
-
1. data를 반환하지 않는 Activity를 시작하고 정상 완료
|
|
80
|
-
|
|
81
|
-
### 기대 결과
|
|
82
|
-
- 반환값의 `data` 필드는 undefined이다
|
|
83
|
-
|
|
84
|
-
## Scenario: 대상 Activity가 extras 없이 종료
|
|
85
|
-
|
|
86
|
-
### 수행 절차
|
|
87
|
-
1. extras를 반환하지 않는 Activity를 시작하고 정상 완료
|
|
88
|
-
|
|
89
|
-
### 기대 결과
|
|
90
|
-
- 반환값의 `extras` 필드는 undefined이다
|
|
91
|
-
|
|
92
|
-
## Scenario: 존재하지 않는 앱으로 Activity 시작 시도
|
|
93
|
-
|
|
94
|
-
### 수행 절차
|
|
95
|
-
1. `Intent.startActivityForResult({ action: "android.intent.action.MAIN", package: "com.nonexistent.app", component: "com.nonexistent.app.MainActivity" })` 호출
|
|
96
|
-
|
|
97
|
-
### 기대 결과
|
|
98
|
-
- ActivityNotFoundException이 발생하여 Promise가 reject된다
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { resolve } from "path";
|
|
2
|
-
|
|
3
|
-
const pkgRoot = resolve(import.meta.dirname, "..");
|
|
4
|
-
const srcDir = resolve(pkgRoot, "src");
|
|
5
|
-
|
|
6
|
-
describe("Slice 1: startActivityForResult TypeScript 인터페이스", () => {
|
|
7
|
-
test("IIntentPlugin에 startActivityForResult 메서드가 정의되어 있다", async () => {
|
|
8
|
-
const mod = await import(resolve(srcDir, "IIntentPlugin.ts"));
|
|
9
|
-
|
|
10
|
-
// IStartActivityForResultOptions 타입이 export되어야 한다
|
|
11
|
-
expect(mod.IStartActivityForResultOptions).toBeUndefined; // interface는 런타임에 없지만 export 확인
|
|
12
|
-
|
|
13
|
-
// IActivityResult 타입이 export되어야 한다
|
|
14
|
-
expect(mod.IActivityResult).toBeUndefined;
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
test("IStartActivityForResultOptions에 필수 필드 action과 선택 필드들이 정의되어 있다", async () => {
|
|
18
|
-
const content = (await import("fs")).readFileSync(resolve(srcDir, "IIntentPlugin.ts"), "utf-8");
|
|
19
|
-
expect(content).toContain("interface IStartActivityForResultOptions");
|
|
20
|
-
expect(content).toMatch(/action\s*:\s*string/);
|
|
21
|
-
expect(content).toMatch(/uri\?\s*:\s*string/);
|
|
22
|
-
expect(content).toMatch(/extras\?\s*:\s*Record<string,\s*unknown>/);
|
|
23
|
-
expect(content).toMatch(/package\?\s*:\s*string/);
|
|
24
|
-
expect(content).toMatch(/component\?\s*:\s*string/);
|
|
25
|
-
expect(content).toMatch(/type\?\s*:\s*string/);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test("IActivityResult에 resultCode, data?, extras? 필드가 정의되어 있다", async () => {
|
|
29
|
-
const content = (await import("fs")).readFileSync(resolve(srcDir, "IIntentPlugin.ts"), "utf-8");
|
|
30
|
-
expect(content).toContain("interface IActivityResult");
|
|
31
|
-
expect(content).toMatch(/resultCode\s*:\s*number/);
|
|
32
|
-
expect(content).toMatch(/data\?\s*:\s*string/);
|
|
33
|
-
expect(content).toMatch(/extras\?\s*:\s*Record<string,\s*unknown>/);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test("IIntentPlugin.startActivityForResult 메서드 시그니처가 올바르다", async () => {
|
|
37
|
-
const content = (await import("fs")).readFileSync(resolve(srcDir, "IIntentPlugin.ts"), "utf-8");
|
|
38
|
-
expect(content).toMatch(/startActivityForResult\s*\(\s*options\s*:\s*IStartActivityForResultOptions\s*\)\s*:\s*Promise<IActivityResult>/);
|
|
39
|
-
});
|
|
40
|
-
});
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { resolve } from "path";
|
|
2
|
-
|
|
3
|
-
const pkgRoot = resolve(import.meta.dirname, "..");
|
|
4
|
-
const srcDir = resolve(pkgRoot, "src");
|
|
5
|
-
|
|
6
|
-
describe("Slice 2: startActivityForResult TypeScript 래퍼 및 웹 stub", () => {
|
|
7
|
-
// Scenario: Intent.startActivityForResult static 메서드 존재
|
|
8
|
-
test("Intent.startActivityForResult static 메서드가 존재한다", async () => {
|
|
9
|
-
const mod = await import(resolve(srcDir, "Intent.ts"));
|
|
10
|
-
expect(typeof mod.Intent.startActivityForResult).toBe("function");
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
// Scenario: 웹에서 startActivityForResult 호출
|
|
14
|
-
test("IntentWeb.startActivityForResult가 resultCode 0으로 resolve한다", async () => {
|
|
15
|
-
const mod = await import(resolve(srcDir, "web/IntentWeb.ts"));
|
|
16
|
-
const web = new mod.IntentWeb();
|
|
17
|
-
|
|
18
|
-
// alert를 mock
|
|
19
|
-
globalThis.alert = vi.fn();
|
|
20
|
-
|
|
21
|
-
const result = await web.startActivityForResult({ action: "test.ACTION" });
|
|
22
|
-
expect(result).toEqual({ resultCode: 0 });
|
|
23
|
-
expect(globalThis.alert).toHaveBeenCalledWith(
|
|
24
|
-
"[Intent] 웹 환경에서는 startActivityForResult를 지원하지 않습니다.",
|
|
25
|
-
);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// index.ts에서 새 타입이 export되는지 확인
|
|
29
|
-
test("index.ts에서 IStartActivityForResultOptions, IActivityResult가 re-export된다", async () => {
|
|
30
|
-
const content = (await import("fs")).readFileSync(resolve(srcDir, "IIntentPlugin.ts"), "utf-8");
|
|
31
|
-
expect(content).toContain("export interface IStartActivityForResultOptions");
|
|
32
|
-
expect(content).toContain("export interface IActivityResult");
|
|
33
|
-
});
|
|
34
|
-
});
|