1# 拉起邮件类应用(startAbilityByType)
2
3本章节介绍如何拉起邮件类应用扩展面板。
4
5## 邮件类应用扩展面板参数说明
6
7startAbilityByType接口中type字段为mail,对应的wantParam参数:
8
9| 参数名                                | 类型                                                         | 必填 | 说明                                                         |
10| ------------------------------------- | ------------------------------------------------------------ | ------ | ------------------------------------------------------------ |
11| email                                 | string[ ]                                                    | 否   | 收件人邮箱地址(支持多个且以逗号分隔)                       |
12| cc                                    | string[ ]                                                    | 否   | 抄收人邮箱地址(支持多个且以逗号分隔)                       |
13| bcc                                   | string[ ]                                                    | 否   | 密送人邮箱地址(支持多个且以逗号分隔)                       |
14| subject                               | string                                                       | 否   | 邮件主题                                                     |
15| body                                  | string                                                       | 否   | 邮件内容                                                     |
16| ability.params.stream                 | string[ ]                                                    | 否   | 邮件附件(附件的uri地址列表)                                |
17| ability.want.params.uriPermissionFlag | [wantConstant.Flags](../reference/apis-ability-kit/js-apis-app-ability-wantConstant.md#flags) | 否   | 给邮件附件赋予至少读权限。邮件附件参数存在时,该参数也必须要传 |
18| sceneType                             | number                                                       | 否   | 意图场景,表明本次请求对应的操作意图。1:发邮件。默认为1。                              |
19
20> **说明:**
21>
22> * 邮件类应用扩展面板中的类型为string的参数,都要经过encodeURI编码。
23>
24> * 邮件类应用扩展面板中的类型为string[]的参数,数组中的元素都要经过encodeURI编码。
25
26## 拉起方开发步骤
271. 导入相关模块。
28    ```ts
29    import { common, wantConstant } from '@kit.AbilityKit';
30    ```
312. 构造接口参数并调用startAbilityByType接口。
32
33    ```ts
34    let context = getContext(this) as common.UIAbilityContext;
35    let wantParam: Record<string, Object> = {
36      'sceneType': 1,
37      'email': [encodeURI('xxx@example.com'),encodeURI('xxx@example.com')], // 收件人邮箱地址,多值以逗号分隔,对数组内容使用encodeURI()方法进行url编码
38      'cc': [encodeURI('xxx@example.com'),encodeURI('xxx@example.com')], // 抄收人邮箱地址,多值以逗号分隔,对数组内容使用encodeURI()方法进行url编码
39      'bcc': [encodeURI('xxx@example.com'),encodeURI('xxx@example.com')], // 密送人邮箱地址,多值以逗号分隔,对数组内容使用encodeURI()方法进行url编码
40      'subject': encodeURI('邮件主题'), // 邮件主题,对内容使用encodeURI()方法进行url编码
41      'body': encodeURI('邮件正文'), // 邮件正文,对内容使用encodeURI()方法进行url编码
42      'ability.params.stream': [encodeURI('附件uri1'),encodeURI('附件uri2')], // 附件uri,多值以逗号分隔,对数组内容使用encodeURI()方法进行url编码
43      'ability.want.params.uriPermissionFlag': wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION
44    };
45    let abilityStartCallback: common.AbilityStartCallback = {
46      onError: (code: number, name: string, message: string) => {
47        console.log(`onError code ${code} name: ${name} message: ${message}`);
48      },
49      onResult: (result)=>{
50        console.log(`onResult result: ${JSON.stringify(result)}`);
51      }
52    }
53
54    context.startAbilityByType("mail", wantParam, abilityStartCallback,
55        (err) => {
56            if (err) {
57                console.error(`startAbilityByType fail, err: ${JSON.stringify(err)}`);
58            } else {
59                console.log(`success`);
60            }
61    });
62    ```
63    效果示例图:
64
65    ![效果示例图](./figures/start-mail-panel.png)
66
67## 目标方开发步骤
68
691. 在module.json5中新增[linkFeature](../quick-start/module-configuration-file.md#skills标签)属性并设置声明当前应用支持的特性功能,从而系统可以从设备已安装应用中找到当前支持该特性的应用,取值范围如下:
70
71    | 取值           | 含义                      |
72    | --------------| ------------------------- |
73    | ComposeMail   | 声明应用支持撰写邮件功能		|
74
75    ```json
76    {
77      "abilities": [
78          {
79          "skills": [
80              {
81              "uris": [
82                  {
83                  "scheme": "mailto", // 这里仅示意,应用需确保这里声明的的uri能被外部正常拉起
84                  "host": "",
85                  "path": "",
86                  "linkFeature": "ComposeMail" // 声明应用支持撰写邮件功能
87                  }
88                ]
89              }
90          ]
91          }
92      ]
93    }
94    ```
95
962. 解析面板传过来的参数并做对应处理。
97
98    ```ts
99    UIAbility.onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void
100    ```
101
102    在参数**want.parameters**中会携带Caller方传入的参数(与调用方传入的有些差异),如下表所示:
103
104    | 参数名  | 类型      | 必填 | 说明                                   |
105    | ------- | --------- | ---- | -------------------------------------- |
106    | email   | string[ ] | 否   | 收件人邮箱地址(支持多个且以逗号分隔) |
107    | cc      | string[ ] | 否   | 抄收人邮箱地址(支持多个且以逗号分隔) |
108    | bcc     | string[ ] | 否   | 密送人邮箱地址(支持多个且以逗号分隔) |
109    | subject | string    | 否   | 邮件主题                               |
110    | body    | string    | 否   | 邮件内容                               |
111    | stream  | string[ ] | 否   | 邮件附件列表(附件的uri地址列表)      |
112
113    > **说明:**
114    >
115    > * 目标方接收的类型为string的参数,都要经过decodeURI解码。
116    >
117    > * 目标方接收的类型为string[]的参数,数组中的元素都要经过decodeURI解码。
118
119**完整示例:**
120
121```ts
122import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
123import { hilog } from '@kit.PerformanceAnalysisKit';
124import { window } from '@kit.ArkUI';
125
126const TAG = 'MailTarget1.EntryAbility'
127
128export default class EntryAbility extends UIAbility {
129    windowStage: window.WindowStage | null = null;
130
131    email: string[] | undefined;
132    cc: string[] | undefined;
133    bcc: string[] | undefined;
134    subject: string | undefined;
135    body: string | undefined;
136    stream: string[] | undefined;
137
138    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
139        hilog.info(0x0000, TAG, `onCreate, want=${JSON.stringify(want)}`);
140        super.onCreate(want, launchParam);
141        this.parseWant(want);
142    }
143
144    onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
145        hilog.info(0x0000, TAG, `onNewWant, want=${JSON.stringify(want)}`);
146        super.onNewWant(want, launchParam);
147        this.parseWant(want);
148        if (!this.windowStage) {
149            hilog.error(0x0000, TAG, 'windowStage is null');
150            this.context.terminateSelf();
151            return;
152        }
153        this.loadPage(this.windowStage);
154    }
155
156    private parseWant(want: Want): void {
157        this.email = this.decodeStringArr(want.parameters?.email as string[]);
158        this.cc = this.decodeStringArr(want.parameters?.cc as string[]);
159        this.bcc = this.decodeStringArr(want.parameters?.bcc as string[]);
160        this.subject = decodeURI(want.parameters?.subject as string);// 使用decodeURI()方法对邮件主题进行url解码,其他字段处理方法相同
161        this.body = decodeURI(want.parameters?.body as string);// 使用decodeURI()方法对邮件内容进行url解码,其他字段处理方法相同
162        this.stream = this.decodeStringArr(want.parameters?.stream as string[]);
163    }
164
165    // 使用decodeURI()方法对string数组内容进行解码
166    private decodeStringArr(source: string[] | undefined): string[] {
167        let target: string[] = [];
168        source?.forEach(e => {
169            target.push(decodeURI(e));
170        })
171        return target;
172    }
173
174    private loadPage(windowStage: window.WindowStage): void {
175        const storage: LocalStorage = new LocalStorage({
176            "email": this.email,
177            "cc": this.cc,
178            "bcc": this.bcc,
179            "subject": this.subject,
180            "body": this.body,
181            "stream": this.stream
182        } as Record<string, Object>);
183
184        windowStage.loadContent('pages/ComposeMailPage', storage);
185
186    }
187
188    onDestroy(): void {
189        hilog.info(0x0000, TAG, `onDestroy`);
190    }
191
192    onWindowStageCreate(windowStage: window.WindowStage): void {
193        hilog.info(0x0000, TAG, `onWindowStageCreate`);
194        this.windowStage = windowStage;
195        this.loadPage(this.windowStage);
196    }
197
198    onWindowStageDestroy(): void {
199        hilog.info(0x0000, TAG, `onWindowStageDestroy`);
200    }
201
202    onForeground(): void {
203        hilog.info(0x0000, TAG, `onForeground`);
204    }
205
206    onBackground(): void {
207        hilog.info(0x0000, TAG, `onBackground`);
208    }
209}
210```