@simplysm/capacitor-plugin-intent 12.16.41
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 +188 -0
- package/android/build.gradle +14 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/kr/co/simplysm/capacitor/intent/IntentPlugin.java +376 -0
- package/dist/src/IIntentPlugin.d.ts +63 -0
- package/dist/src/IIntentPlugin.js +1 -0
- package/dist/src/Intent.d.ts +64 -0
- package/dist/src/Intent.js +80 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- package/dist/src/web/IntentWeb.d.ts +19 -0
- package/dist/src/web/IntentWeb.js +24 -0
- package/package.json +26 -0
- package/src/IIntentPlugin.ts +65 -0
- package/src/Intent.ts +90 -0
- package/src/index.ts +2 -0
- package/src/web/IntentWeb.ts +34 -0
- package/tests/slice1-directory-and-config.spec.ts +50 -0
- package/tests/slice2-java-renaming.spec.ts +34 -0
- package/tests/slice3-typescript-renaming.spec.ts +76 -0
- package/tests/slice4-docs-and-deprecation.spec.ts +31 -0
- package/tests/slice5-start-activity-for-result-android.spec.md +98 -0
- package/tests/slice5-start-activity-for-result-types.spec.ts +40 -0
- package/tests/slice6-start-activity-for-result-web.spec.ts +34 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,98 @@
|
|
|
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된다
|
|
@@ -0,0 +1,40 @@
|
|
|
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
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
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
|
+
});
|