使用说明
- 第一次打开应用进入启动页,显示隐私协议弹框。
- 第一次打开应用进入启动页,点击隐私协议链接跳转隐私协议页面。
- 第一次打开应用进入启动页,显示隐私协议弹框,点击不同意,退出应用。
- 第一次打开应用进入启动页,显示隐私协议弹框,点击同意,3秒后跳转到广告页。
- 进入广告页,2秒后自动跳转应用首页。
- 进入广告页,点击右上角跳过按钮,跳转应用首页。
相关概念
-
首选项:首选项为应用提供Key-Value键值型的数据处理能力,支持应用持久化轻量级数据,并对其修改和查询。数据存储形式为键值对,键的类型为字符串型,值的存储数据类型包括数字型、字符型、布尔型以及这3种类型的数组类型。
-
自定义弹窗:通过CustomDialogController类显示自定义弹窗。
-
页面路由:提供通过不同的url访问不同的页面,包括跳转到应用内的指定页面、用应用内的某个页面替换当前页面、返回上一页面或指定的页面等。
效果截图
代码结构
CommonConstants
export default class CommonConstants {
/**
* The main ability tag.
*/
static readonly ENTRY_ABILITY_TAG: string = 'EntryAbility';
/**
* The launcher page tag.
*/
static readonly LAUNCHER_PAGE_TAG: string = 'LauncherPage';
/**
* The advertsing page tag.
*/
static readonly ADVERTISING_PAGE_TAG: string = 'AdvertisingPage';
/**
* The custom dialog component tag.
*/
static readonly CUSTOM_DIALOG_TAG: string = 'CustomDialogComponent';
/**
* Preference saved key.
*/
static readonly PREFERENCES_KEY_PRIVACY: string = 'isPrivacy';
/**
* Preference saved file name.
*/
static readonly PREFERENCES_FILE_NAME: string = 'myStore';
/**
* Launcher page count down.
*/
static readonly LAUNCHER_DELAY_TIME: number = 3000;
/**
* Image logo top margin.
*/
static readonly LAUNCHER_IMAGE_MARGIN_TOP: string = '16.2%';
/**
* Healthy living text spacing.
*/
static readonly LAUNCHER_LIFE_TEXT_SPACING: number = 0.1;
/**
* Healthy living title text top margin.
*/
static readonly LAUNCHER_TEXT_TITLE_MARGIN_TOP: string = '0.5%';
/**
* Content control height.
*/
static readonly LAUNCHER_TEXT_INTRODUCE_HEIGHT: string = '2.7%';
/**
* Healthy living instructions.
*/
static readonly LAUNCHER_TEXT_INTRODUCE_SPACING: number = 3.4;
/**
* Healthy living content top margin.
*/
static readonly LAUNCHER_TEXT_INTRODUCE_MARGIN_TOP: string = '1.3%';
/**
* Interval execution time.
*/
static readonly ADVERTISING_INTERVAL_TIME: number = 1000;
/**
* Advertising page url.
*/
static readonly ADVERTISING_PAGE_URL: string = 'pages/AdvertisingPage';
/**
* Display countdown seconds.
*/
static readonly ADVERTISING_COUNT_DOWN_SECONDS: number = 2;
/**
* Count down text spacing.
*/
static readonly ADVERTISING_TITLE_TEXT_LETTER_SPACING: number = 0.05;
/**
* Advertising page healthy text spacing.
*/
static readonly ADVERTISING_HEALTHY_LIFE_TEXT_SPACING: number = 0.1;
/**
* Advertising page health description text spacing.
*/
static readonly ADVERTISING_TEXT_INTRODUCE_LETTER_SPACING: number = 3.4;
/**
* Advertising page health description text top margin.
*/
static readonly ADVERTISING_TEXT_INTRODUCE_MARGIN_TOP: string = '0.4%';
/**
* Column container left margin.
*/
static readonly ADVERTISING_COLUMN_MARGIN_LEFT: string = '3.1%';
/**
* Row container bottom margin.
*/
static readonly ADVERTISING_ROW_MARGIN_BOTTOM: string = '3.1%';
/**
* Dialog component width the percentage of the 90.
*/
static readonly DIALOG_COMPONENT_WIDTH_PERCENT: string = '90%';
/**
* Dialog title text weight.
*/
static readonly DIALOG_TITLE_FONT_WEIGHT: number = 600;
/**
* Dialog width the percentage of the 93.3.
*/
static readonly DIALOG_WIDTH_PERCENT: string = '93.3%';
/**
* Dialog border radius.
*/
static readonly DIALOG_BORDER_RADIUS: number = 24;
/**
* Dialog component bottom margin,
*/
static readonly DIALOG_ROW_MARGIN_BOTTOM: string = '3.1%';
/**
* Dialog y-axis offset distance.
*/
static readonly DIALOG_CONTROLLER_DY_OFFSET: number = -24;
/**
* Width the percentage of the 100.
*/
static readonly FULL_WIDTH: string = '100%';
/**
* Height the percentage of the 100.
*/
static readonly FULL_HEIGHT: string = '100%';
/**
* Privacy page url.
*/
static readonly PRIVACY_PAGE_URL: string = 'pages/PrivacyPage';
/**
* App home page url.
*/
static readonly APP_HOME_PAGE_URL: string = 'pages/AppHomePage';
/**
* Common layout weight.
*/
static readonly COMMON_LAYOUT_WEIGHT: number = 1;
}
GlobalContext
export class GlobalContext {
private constructor() { }
private static instance: GlobalContext;
private _objects = new Map<string, Object>();
public static getContext(): GlobalContext {
if (!GlobalContext.instance) {
GlobalContext.instance = new GlobalContext();
}
return GlobalContext.instance;
}
getObject(value: string): Object | undefined {
return this._objects.get(value);
}
setObject(key: string, objectClass: Object): void {
this._objects.set(key, objectClass);
}
}
Logger
import { hilog } from '@kit.PerformanceAnalysisKit';
class Logger {
private domain: number;
private prefix: string;
private format: string = '%{public}s, %{public}s';
/**
* constructor.
*
* @param Prefix Identifies the log tag.
* @param domain Domain Indicates the service domain, which is a hexadecimal integer ranging from 0x0 to 0xFFFFF.
*/
constructor(prefix: string = 'MyApp', domain: number = 0xFF00) {
this.prefix = prefix;
this.domain = domain;
}
debug(...args: string[]): void {
hilog.debug(this.domain, this.prefix, this.format, args);
}
info(...args: string[]): void {
hilog.info(this.domain, this.prefix, this.format, args);
}
warn(...args: string[]): void {
hilog.warn(this.domain, this.prefix, this.format, args);
}
error(...args: string[]): void {
hilog.error(this.domain, this.prefix, this.format, args);
}
}
export default new Logger('FirstStartDemo', 0xFF00)
AdvertisingPage
import { router } from '@kit.ArkUI';
import Logger from '../common/utils/Logger';
import CommonConstants from '../common/constants/CommonConstants';
/**
* Stay on the advertising page for a few seconds to jump to the home page.
*/
@Entry
@Component
struct AdvertisingPage {
@State countDownSeconds: number = CommonConstants.ADVERTISING_COUNT_DOWN_SECONDS;
private timeId: number = 0;
onPageShow() {
this.timeId = setInterval(() => {
if (this.countDownSeconds == 0) {
this.jumpToAppHomePage();
} else {
this.countDownSeconds--;
}
}, CommonConstants.ADVERTISING_INTERVAL_TIME);
}
onPageHide() {
router.clear();
clearInterval(this.timeId);
}
/**
* Jump to app home page.
*/
jumpToAppHomePage() {
router.pushUrl({
url: CommonConstants.APP_HOME_PAGE_URL
}).catch((error: Error) => {
Logger.error(CommonConstants.ADVERTISING_PAGE_TAG, 'AdvertisingPage pushUrl error ' + JSON.stringify(error));
});
}
build() {
Stack({ alignContent: Alignment.Top }) {
Image($r('app.media.ic_advertising_background'))
.width(CommonConstants.FULL_WIDTH)
.height(CommonConstants.FULL_HEIGHT)
Text($r('app.string.advertising_text_title', this.countDownSeconds))
.fontColor(Color.White)
.fontSize($r('app.float.advertising_text_font_size'))
.letterSpacing(CommonConstants.ADVERTISING_TITLE_TEXT_LETTER_SPACING)
.backgroundColor($r('app.color.advertising_text_background_color'))
.border({
radius: $r('app.float.advertising_text_radius'),
width: $r('app.float.advertising_text_border_width'),
color: Color.White
})
.margin({
top: $r('app.float.advertising_title_text_margin_top'),
left: $r('app.float.advertising_title_text_margin_left')
})
.padding({
left: $r('app.float.advertising_text_padding_left'),
top: $r('app.float.advertising_text_padding_top'),
right: $r('app.float.advertising_text_padding_left'),
bottom: $r('app.float.advertising_text_padding_bottom')
})
.onClick(() => {
this.jumpToAppHomePage();
})
Row() {
Image($r('app.media.ic_logo'))
.width($r('app.float.advertising_image_width'))
.height($r('app.float.advertising_image_height'))
.margin({ bottom: CommonConstants.ADVERTISING_ROW_MARGIN_BOTTOM })
Column() {
Text($r('app.string.healthy_life_text'))
.bottomTextStyle(FontWeight.Bolder,
CommonConstants.ADVERTISING_HEALTHY_LIFE_TEXT_SPACING,
$r('app.float.advertising_text_title_size'),
$r('app.color.advertising_text_title_color'))
Text($r('app.string.healthy_life_introduce'))
.bottomTextStyle(FontWeight.Normal,
CommonConstants.ADVERTISING_TEXT_INTRODUCE_LETTER_SPACING,
$r('app.float.advertising_text_introduce_size'),
$r('app.color.launcher_text_introduce_color'))
.opacity($r('app.float.advertising_text_opacity'))
.margin({ top: CommonConstants.ADVERTISING_TEXT_INTRODUCE_MARGIN_TOP })
}
.alignItems(HorizontalAlign.Start)
.margin({
left: CommonConstants.ADVERTISING_COLUMN_MARGIN_LEFT,
bottom: CommonConstants.ADVERTISING_ROW_MARGIN_BOTTOM
})
}
.alignItems(VerticalAlign.Bottom)
.height(CommonConstants.FULL_HEIGHT)
}
.width(CommonConstants.FULL_WIDTH)
.height(CommonConstants.FULL_HEIGHT)
}
}
// Bottom text common style.
@Extend(Text) function bottomTextStyle (fontWeight: number,
textAttribute: number, fontSize: Resource, fontColor: Resource) {
.fontWeight(fontWeight)
.letterSpacing(textAttribute)
.fontSize(fontSize)
.fontColor(fontColor)
}
AppHomePage
import CommonConstants from '../common/constants/CommonConstants';
/**
* App home page.
*/
@Entry
@Component
struct AppHomePage {
build() {
Stack() {
Image($r('app.media.ic_home_page_background'))
.width(CommonConstants.FULL_WIDTH)
.height(CommonConstants.FULL_HEIGHT)
Text($r('app.string.home_page_text'))
.fontSize($r('app.float.home_page_text_size'))
.fontColor($r('app.color.home_page_text_color'))
.fontWeight(FontWeight.Bold)
.textAlign(TextAlign.Center)
.height(CommonConstants.FULL_HEIGHT)
.width(CommonConstants.FULL_WIDTH)
}
}
}
LauncherPage
import { preferences } from '@kit.ArkData';
import { common } from '@kit.AbilityKit';
import { router } from '@kit.ArkUI';
import Logger from '../common/utils/Logger';
import CommonConstants from '../common/constants/CommonConstants';
import CustomDialogComponent from '../view/CustomDialogComponent';
import { GlobalContext } from '../common/utils/GlobalContext';
/**
* The LauncherPage is the entry point of the application and shows how to develop the LauncherPage.
* Stay on the LauncherPage for a few seconds to jump to the AdvertisingPage.
* Developers can replace the background image.
*/
@Entry
@Component
struct LauncherPage {
private context?: common.UIAbilityContext;
private timerId: number = 0;
private isJumpToAdvertising: boolean = false;
dialogController: CustomDialogController = new CustomDialogController({
builder: CustomDialogComponent(
{
cancel: () => {
this.onCancel();
},
confirm: () => {
this.onConfirm();
}
}),
alignment: DialogAlignment.Bottom,
offset: { dx: 0, dy: CommonConstants.DIALOG_CONTROLLER_DY_OFFSET },
customStyle: true,
autoCancel: false
});
onCancel() {
// Exit the application.
this.context?.terminateSelf();
}
onConfirm() {
// Save privacy agreement status.
this.saveIsPrivacy();
this.jumpToAdvertisingPage();
}
onPageHide() {
if (this.isJumpToAdvertising) {
router.clear();
}
// globalThis.isJumpPrivacy = true;
GlobalContext.getContext().setObject('isJumpPrivacy', true);
clearTimeout(this.timerId);
}
/**
* Jump to advertising page.
*/
jumpToAdvertisingPage() {
this.timerId = setTimeout(() => {
this.isJumpToAdvertising = true;
router.pushUrl({
url: CommonConstants.ADVERTISING_PAGE_URL
}).catch((error: Error) => {
Logger.error(CommonConstants.LAUNCHER_PAGE_TAG, 'LauncherPage pushUrl error ' + JSON.stringify(error));
});
}, CommonConstants.LAUNCHER_DELAY_TIME);
}
saveIsPrivacy() {
let preferences: Promise<preferences.Preferences> = this.getDataPreferences(this);
preferences.then((result: preferences.Preferences) => {
let privacyPut = result.put(CommonConstants.PREFERENCES_KEY_PRIVACY, false);
result.flush();
privacyPut.then(() => {
Logger.info(CommonConstants.LAUNCHER_PAGE_TAG, 'Put the value of startup Successfully.');
}).catch((err: Error) => {
Logger.error(CommonConstants.LAUNCHER_PAGE_TAG, 'Put the value of startup Failed, err: ' + err);
});
}).catch((err: Error) => {
Logger.error(CommonConstants.LAUNCHER_PAGE_TAG, 'Get the preferences Failed, err: ' + err);
});
}
onPageShow() {
this.context = getContext(this) as common.UIAbilityContext;
// Get the operation class for saving data.
this.getDataPreferences(this).then((preferences: preferences.Preferences) => {
preferences.get(CommonConstants.PREFERENCES_KEY_PRIVACY, true).then((value: preferences.ValueType) => {
Logger.info(CommonConstants.LAUNCHER_PAGE_TAG, 'onPageShow value: ' + value);
if (value) {
// let isJumpPrivacy: boolean = globalThis.isJumpPrivacy ?? false;
let isJumpPrivacy: boolean = (GlobalContext.getContext().getObject('isJumpPrivacy') as boolean) ?? false;
if (!isJumpPrivacy) {
this.dialogController.open();
}
} else {
this.jumpToAdvertisingPage();
}
});
});
}
/**
* Get data preferences action.
*/
getDataPreferences(common: Object) {
return preferences.getPreferences(getContext(common), CommonConstants.PREFERENCES_FILE_NAME);
}
build() {
Stack() {
Image($r('app.media.ic_launcher_background'))
.width(CommonConstants.FULL_WIDTH)
.height(CommonConstants.FULL_HEIGHT)
Column() {
Image($r('app.media.ic_logo'))
.width($r('app.float.launcher_logo_size'))
.height($r('app.float.launcher_logo_size'))
.margin({ top: CommonConstants.LAUNCHER_IMAGE_MARGIN_TOP })
Text($r('app.string.healthy_life_text'))
.width($r('app.float.launcher_life_text_width'))
.height($r('app.float.launcher_life_text_height'))
.healthyLifeTextStyle(FontWeight.Bold,
CommonConstants.LAUNCHER_LIFE_TEXT_SPACING,
$r('app.float.launcher_text_title_size'),
$r('app.color.launcher_text_title_color'))
.margin({ top: CommonConstants.LAUNCHER_TEXT_TITLE_MARGIN_TOP })
Text($r('app.string.healthy_life_introduce'))
.height(CommonConstants.LAUNCHER_TEXT_INTRODUCE_HEIGHT)
.healthyLifeTextStyle(FontWeight.Normal,
CommonConstants.LAUNCHER_TEXT_INTRODUCE_SPACING,
$r('app.float.launcher_text_introduce_size'),
$r('app.color.launcher_text_introduce_color'))
.opacity($r('app.float.launcher_text_opacity'))
.margin({ top: CommonConstants.LAUNCHER_TEXT_INTRODUCE_MARGIN_TOP })
}
.height(CommonConstants.FULL_HEIGHT)
.width(CommonConstants.FULL_WIDTH)
}
}
}
// Healthy living text common styles.
@Extend(Text) function healthyLifeTextStyle (fontWeight: number,
textAttribute: number, fontSize: Resource, fontColor: Resource) {
.fontWeight(fontWeight)
.letterSpacing(textAttribute)
.fontSize(fontSize)
.fontColor(fontColor)
}
PrivacyPage
import { router } from '@kit.ArkUI';
import CommonConstants from '../common/constants/CommonConstants';
import { GlobalContext } from '../common/utils/GlobalContext';
/**
* The privacy agreement page displays the agreement content.
*/
@Entry
@Component
struct PrivacyPage {
build() {
Column() {
Text($r('app.string.privacy_text_title'))
.fontSize($r('app.float.privacy_text_title_size'))
.textAlign(TextAlign.Center)
.margin({
top: $r('app.float.privacy_text_margin_top'),
bottom: $r('app.float.privacy_text_margin_bottom')
})
Text($r('app.string.privacy_text_content'))
.fontSize($r('app.float.dialog_common_text_size'))
.margin({
left: $r('app.float.privacy_text_content_left'),
right: $r('app.float.privacy_text_content_right')
})
Text($r('app.string.privacy_back'))
.fontColor($r('app.color.privacy_back_text'))
.fontSize($r('app.float.privacy_back_text_size'))
.textAlign(TextAlign.Center)
.fontWeight(FontWeight.Medium)
.onClick(() => {
// globalThis.isJumpPrivacy = false;
GlobalContext.getContext().setObject('isJumpPrivacy', false);
router.back();
})
.margin({ top: $r('app.float.privacy_bottom_text_margin') })
}
.justifyContent(FlexAlign.Center)
.height(CommonConstants.FULL_HEIGHT)
}
onBackPress() {
// globalThis.isJumpPrivacy = false;
GlobalContext.getContext().setObject('isJumpPrivacy', false);
}
}
CustomDialogComponent
import { router } from '@kit.ArkUI';
import Logger from '../common/utils/Logger';
import CommonConstants from '../common/constants/CommonConstants';
import { GlobalContext } from '../common/utils/GlobalContext';
/**
* Custom pop-up window.
*/
@CustomDialog
export default struct CustomDialogComponent {
controller: CustomDialogController = new CustomDialogController({'builder': ''});
cancel: Function = () => {};
confirm: Function = () => {};
build() {
Column() {
Text($r('app.string.dialog_text_title'))
.width(CommonConstants.DIALOG_COMPONENT_WIDTH_PERCENT)
.fontColor($r('app.color.dialog_text_color'))
.fontSize($r('app.float.dialog_text_privacy_size'))
.textAlign(TextAlign.Center)
.fontWeight(CommonConstants.DIALOG_TITLE_FONT_WEIGHT)
.margin({
top: $r('app.float.dialog_text_privacy_top'),
bottom: $r('app.float.dialog_text_privacy_bottom')
})
Text($r('app.string.dialog_text_privacy_content'))
.fontSize($r('app.float.dialog_common_text_size'))
.width(CommonConstants.DIALOG_COMPONENT_WIDTH_PERCENT)
Text($r('app.string.dialog_text_privacy_statement'))
.width(CommonConstants.DIALOG_COMPONENT_WIDTH_PERCENT)
.fontColor($r('app.color.dialog_text_statement_color'))
.fontSize($r('app.float.dialog_common_text_size'))
.onClick(() => {
// globalThis.isJumpPrivacy = true;
this.controller.close();
GlobalContext.getContext().setObject('isJumpPrivacy', true);
router.pushUrl({
url: CommonConstants.PRIVACY_PAGE_URL
}).catch((error: Error) => {
Logger.error(CommonConstants.CUSTOM_DIALOG_TAG, 'CustomDialog pushUrl error ' + JSON.stringify(error));
});
})
Text($r('app.string.dialog_text_declaration_prompt'))
.width(CommonConstants.DIALOG_COMPONENT_WIDTH_PERCENT)
.fontColor($r('app.color.dialog_text_color'))
.fontSize($r('app.float.dialog_common_text_size'))
.opacity($r('app.float.dialog_text_opacity'))
.margin({ bottom: $r('app.float.dialog_text_declaration_bottom') })
Row() {
Text($r('app.string.dialog_button_disagree'))
.fancy()
.onClick(() => {
this.controller.close();
this.cancel();
})
Blank()
.backgroundColor($r('app.color.dialog_blank_background_color'))
.width($r('app.float.dialog_blank_width'))
.height($r('app.float.dialog_blank_height'))
Text($r('app.string.dialog_button_agree'))
.fancy()
.onClick(() => {
this.controller.close();
this.confirm();
})
}
.margin({ bottom: CommonConstants.DIALOG_ROW_MARGIN_BOTTOM })
}
.width(CommonConstants.DIALOG_WIDTH_PERCENT)
.borderRadius(CommonConstants.DIALOG_BORDER_RADIUS)
.backgroundColor(Color.White)
}
}
// Common text styles.
@Extend(Text) function fancy () {
.fontColor($r("app.color.dialog_fancy_text_color"))
.fontSize($r("app.float.dialog_fancy_text_size"))
.textAlign(TextAlign.Center)
.fontWeight(FontWeight.Medium)
.layoutWeight(CommonConstants.COMMON_LAYOUT_WEIGHT)
}