0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

B站添加鴻蒙服務(wù)卡片教程

華為麒麟 ? 來(lái)源:鴻蒙技術(shù)社區(qū) ? 作者:亮子力 ? 2021-08-12 10:07 ? 次閱讀

????????6 月 2 日鴻蒙發(fā)布,今年的六月已經(jīng)被鴻蒙刷屏了。從安卓到鴻蒙,最直觀的變化應(yīng)該就是服務(wù)卡片了。我也是在學(xué)習(xí)鴻蒙的同時(shí),實(shí)際體驗(yàn)一下服務(wù)卡片的開(kāi)發(fā)。

接下來(lái)分享下我的制作過(guò)程,我使用的開(kāi)發(fā)環(huán)境是:

IDE:DevEco Studio 2.1 Release

SDK:API Version 5

軟件安裝和項(xiàng)目建立的部分就跳過(guò)了,相信大家都比較熟悉了。直奔主題服務(wù)卡片的制作。

服務(wù)卡片設(shè)計(jì)

首先要先了解服務(wù)卡片,都有哪些尺寸,支持哪些組件,使用什么語(yǔ)言。然后規(guī)劃好要實(shí)現(xiàn)哪些功能。

①尺寸規(guī)格

服務(wù)卡片有 4 種尺寸,分別是微卡片、小卡片、中卡片、大卡片。官方提供了 4 種基礎(chǔ)模板,12 種高級(jí)模板可以選擇。

基礎(chǔ)模板如下圖:

78df57c6-fab5-11eb-9bcf-12bb97331649.png

②功能設(shè)計(jì)

服務(wù)卡片設(shè)計(jì)的初衷就是信息顯示、服務(wù)直達(dá)。依照這個(gè)原則,我找了幾個(gè) Bilibili 中我比較常用的功能,來(lái)制作服務(wù)卡片,比如追番列表。

③開(kāi)發(fā)語(yǔ)言

看下表就一目了然了,就是推薦 JS。表格來(lái)源:

7fec67de-fab5-11eb-9bcf-12bb97331649.png

界面實(shí)現(xiàn)

本著學(xué)習(xí)的目的,卡片界面就不使用模板了。不過(guò)我們還是要通過(guò) IDE→File→New→Service Widget 來(lái)添加服務(wù)卡片,這樣添加 IDE 會(huì)自動(dòng)添加配置和管理相關(guān)文件。

然后服務(wù)卡片的界面重新編寫(xiě)。服務(wù)卡片常用的的容器組件有 div、list、stack、swiper 等。

我使用了 4 種尺寸的卡片,并盡可能的使用到所有的容器組件。

①div:基礎(chǔ)容器組件

就是用來(lái)劃分區(qū)域的。比較常用。比如追番服務(wù)卡片。

代碼如下:

《div class=“div_root” 》《!--在服務(wù)卡片設(shè)置一個(gè) 根div 橫向布局--》

《div class=“div_container”》《!--在根div 橫向放置4個(gè)div,每個(gè)div內(nèi)部從上往下排列--》

《image class=“item_image” src=“{{ src1 }}” onclick=“routerEvent1”》《/image》

《text class=“item_title”》{{ itemTitle1 }}《/text》

《text class=“item_content”》{{ itemContent1 }}《/text》

《/div》

《div class=“div_container”》《!--第二列--》

《image class=“item_image” src=“{{ src2 }}” onclick=“routerEvent2”》《/image》

《text class=“item_title”》{{ itemTitle2 }}《/text》

《text class=“item_content”》{{ itemContent2 }}《/text》

《/div》

《div class=“div_container”》《!--第三列--》

《image class=“item_image” src=“{{ src3 }}” onclick=“routerEvent3”》《/image》

《text class=“item_title”》{{ itemTitle3 }}《/text》

《text class=“item_content”》{{ itemContent3 }}《/text》

《/div》

《div class=“div_container”》《!--第四列--》

《image class=“item_image” src=“{{ src4 }}” onclick=“routerEvent4”》《/image》

《text class=“item_title”》{{ itemTitle4 }}《/text》

《text class=“item_content”》{{ itemContent4 }}《/text》

《/div》

《/div》

.div_root {

flex-direction: row; /*flex容器主軸方向,row:水平方向從左到右。*/

justify-content: center; /*flex容器當(dāng)前行的主軸對(duì)齊格式,center:項(xiàng)目位于容器的中心。*/

margin:6px; /*外邊距屬性:只有一個(gè)值時(shí),這個(gè)值會(huì)被指定給全部的四個(gè)邊。*/

border-radius: 10px; /*設(shè)置元素的外邊框圓角半徑。*/

}

.div_container {

flex-direction: column; /*flex容器主軸方向,column:垂直方向從上到下。*/

justify-content: flex-start; /*flex容器當(dāng)前行的主軸對(duì)齊格式,flex-start:項(xiàng)目位于容器的開(kāi)頭。*/

margin:6px;

}

.item_image {

height: 60%; /*卡片在不同設(shè)備,尺寸會(huì)發(fā)生變化,所以最好使用百分比進(jìn)行標(biāo)注。*/

border-radius: 10px;

background-color: #F1F3F5; /*設(shè)置背景顏色。*/

}

@media (dark-mode: true) { /*當(dāng)前系統(tǒng)為深色模式時(shí),使用這里的配置,如果沒(méi)有顏色設(shè)置,可以不設(shè)置*/

.item_image {

height: 60%;

border-radius: 10px;

background-color: #202224;

}

}

.item_title {

margin-top: 10px; /*設(shè)置上邊距。*/

font-size: 12px; /*設(shè)置文本的尺寸。*/

font-weight: bold; /*設(shè)置文本的字體粗細(xì)。取值[100, 900],默認(rèn)為400。*/

max-lines:1; /*設(shè)置文本的最大行數(shù)。*/

text-overflow: ellipsis; /*根據(jù)父容器大小顯示,顯示不下的文本用省略號(hào)代替。需配合max-lines使用。*/

color: #e5000000; /*設(shè)置文本的顏色。*/

}

.item_content {

margin-top: 5px;

font-size: 9px;

font-weight: bold;

text-overflow: ellipsis;

max-lines:1;

color: #99000000;

}

Note:其實(shí)這個(gè)服務(wù)卡片的布局,每一列的內(nèi)容都是相同的,是應(yīng)該使用 list 組件的。

②list:列表容器組件

就如上面所說(shuō)的連續(xù)相同的部分,可以使用這個(gè)組件,List 不但可以顯示更多的內(nèi)容,而且代碼更少。

代碼如下:

《list class=“l(fā)ist”》

《list-item for=“{{cards}}” class=“l(fā)ist-item”》

《div class=“div” onclick=“sendRouteEvent”》

《image class=“item_image” src=“{{ $item.pic }}”》《/image》

《text class=“item_name”》{{ $item.name }}《/text》

《text class=“item_title”》{{ $item.title }}《/text》

《/div》

《/list-item》

《/list》

.list{

align-items:center; /*list每一列交叉軸上的對(duì)齊格式:元素在交叉軸居中*/

}

.list-item{

border-radius: 15px;

background-color: #f2f2f2;

margin-bottom: 5px;

}

.div{

flex-direction: column;

}

.item_image {

border-top-right-radius: 15px;

border-top-left-radius: 15px;

}

.item_name {

margin:5px 8px 0px;

font-size: 12px;

color: #262626;

}

.item_title{

margin:3px 8px 8px;

font-size: 10px;

color: #AAAAAA;

max-lines: 2;

text-overflow: ellipsis; /* 省略號(hào) */

}

③stack:堆疊容器組件

簡(jiǎn)單來(lái)說(shuō)就是可以在一張圖片上堆疊顯示另一張圖片,例如下圖藍(lán)框的圖片覆蓋在紅框圖片的上面。

④swiper:滑動(dòng)容器組件

正常情況下 swiper 是可以實(shí)現(xiàn)上下、左右滑動(dòng)操作的。但是放置在桌面上的服務(wù)卡片,在左右滑動(dòng)操作的時(shí)候,會(huì)使系統(tǒng)分不清楚用戶(hù)是要左右滑動(dòng)屏幕,還是左右滑動(dòng)卡片。

所以目前服務(wù)卡片的 swiper 容器是不支持手勢(shì)滑動(dòng)切換子組件的。下圖是通過(guò)點(diǎn)擊圖片側(cè)面的控制條實(shí)現(xiàn)上下滑動(dòng)的。

但是我個(gè)人覺(jué)得上下滑動(dòng)其實(shí)還是挺好用的,畢竟在 list 組件上是可以上下滑動(dòng)的,只可惜目前還不支持。

總結(jié):服務(wù)卡片的設(shè)計(jì)比較簡(jiǎn)單,零基礎(chǔ)也沒(méi)關(guān)系,官方還貼心的準(zhǔn)備了模板。只要挑選模板,設(shè)置變量也能快速構(gòu)建。

API 數(shù)據(jù)請(qǐng)求

卡片設(shè)計(jì)好之后,就需要通過(guò) Bilibili 的 API 來(lái)獲取數(shù)據(jù)了。主要就是給權(quán)限添加依賴(lài),然后發(fā)送網(wǎng)絡(luò)請(qǐng)求,通過(guò) API 獲取 JSON 的返回值,然后解析 JSON 得到我們需要的數(shù)據(jù)。

①添加聯(lián)網(wǎng)權(quán)限

要在 config.json 配置文件的 module 中添加:“reqPermissions”: [{“name”:“ohos.permission.INTERNET”}]。

{

。。。 。。。

“module”: {

。。。 。。。

“reqPermissions”: [{“name”:“ohos.permission.INTERNET”}]

}

}

②添加依賴(lài)包

找到 entry/build.gradle 文件,在 dependencies 下添加:

dependencies {

implementation fileTree(dir: ‘libs’, include: [‘*.jar’, ‘*.har’])

testImplementation ‘junit4.13’

ohosTestImplementation ‘com.huawei.ohos.testkit1.0.0.100’

// ZZRHttp 可以單獨(dú)一個(gè)進(jìn)程進(jìn)行http請(qǐng)求

implementation ‘com.zzrv5.zzrhttp1.0.1’

// fastjson 可以解析JSON格式

implementation group: ‘com.alibaba’, name: ‘fastjson’, version: ‘1.2.75’

}

③http 請(qǐng)求

以獲取粉絲數(shù)為例,如果在瀏覽器中輸入 https://api.bilibili.com/x/relation/stat?vmid=383565952。

8343abae-fab5-11eb-9bcf-12bb97331649.png

其中 vmid:是要查詢(xún)的用戶(hù) ID,follower 的值就是粉絲數(shù)。

網(wǎng)絡(luò)訪問(wèn)我們可以使用 HttpURLConnection,或者 okhttp 等依賴(lài)包,但是需要開(kāi)啟子線程、處理異常等操作,所以這里使用的是 ZZR 老師封裝好的 ZZRHttp。

代碼實(shí)現(xiàn):

//獲取Bilibili粉絲數(shù),這里就要用到第二步我們添加的ZZRHttp

String url = “https://api.bilibili.com/x/relation/stat?vmid=383565952”;

ZZRHttp.get(url, new ZZRCallBack.CallBackString() {

@Override

public void onFailure(int i, String s) {

HiLog.info(TAG, “API返回失敗”);

}

@Override

public void onResponse(String s) {

HiLog.info(TAG, “API返回成功”);

// 如果返回成功,返回的結(jié)果就會(huì)保存在 String s 中。

// s = {“code”:0,“message”:“0”,“ttl”:1,“data”:{“mid”:383565952,“following”:70,“whisper”:0,“black”:0,“follower”:5384}}

}

});

④解析 JSON

得到的是 JSON 格式的返回值,要得到 follower 的值,還需要對(duì) JSON 進(jìn)行數(shù)據(jù)解析。

先按照 JSON 的內(nèi)容,生成 JAVA 類(lèi)??梢宰约簩?xiě),也可以百度搜 ”JSON 生成 Java 實(shí)體類(lèi)“,可直接生成。

代碼如下:

public class BilibiliFollower {

public static class Data{

private int follower;

public int getFollower() {

return follower;

}

public void setFollower(int follower) {

this.follower = follower;

}

}

private BilibiliFollower.Data data;

public BilibiliFollower.Data getData() {

return data;

}

public void setData(BilibiliFollower.Data data) {

this.data = data;

}

}

//解析JSON,使用第二步我們添加的fastjson包try {

//1.調(diào)用fastjson解析,結(jié)果保存在JSON對(duì)應(yīng)的類(lèi)

BilibiliFollower bilibiliFollower = JSON.parseObject(s,BilibiliFollower.class);

//2.get方法獲取解析內(nèi)容

BilibiliFollower.Data data= bilibiliFollower.getData();

System.out.println(“解析成功”+data.getFollower());

} catch (Exception e) {

HiLog.info(TAG, “解析失敗”);

}

總結(jié):一定要添加聯(lián)網(wǎng)權(quán)限不然是獲取不到數(shù)據(jù)的。添加了 2 個(gè)依賴(lài)包,可以很方便的提取數(shù)據(jù)。

獲取其他的卡片數(shù)據(jù)的方式同理,不過(guò)代碼比較多,就不一一展示了,感興趣可以下載全量代碼看。

數(shù)據(jù)更新

要想將數(shù)據(jù)更新到服務(wù)卡片,得先了解服務(wù)卡片的運(yùn)作機(jī)制。如果是通過(guò) IDE→File→New→Service Widget 添加的服務(wù)卡片,那么在 MainAbility 中會(huì)添加卡片的生命周期回調(diào)方法。

參考下面的代碼:

public class MainAbility extends Ability {

。。。 。。。

protected ProviderFormInfo onCreateForm(Intent intent) {。。。}//在服務(wù)卡片上右擊》》服務(wù)卡片(或上滑)時(shí),通知接口

protected void onUpdateForm(long formId) {。。。}//在服務(wù)卡片請(qǐng)求更新,定時(shí)更新時(shí),通知接口

protected void onDeleteForm(long formId) {。。}//在服務(wù)卡片被刪除時(shí),通知接口

protected void onTriggerFormEvent(long formId, String message) {。。。}//JS服務(wù)卡片click時(shí),通知接口

}

①定時(shí)更新

按照上述分析,我們只需要在 config.json 中開(kāi)啟服務(wù)卡片的周期性更新,在 onUpdateForm(long formId) 方法下執(zhí)行數(shù)據(jù)獲取更新。

config.json 文件“abilities”的 forms 模塊配置細(xì)節(jié)如下:

“forms”: [

{

“jsComponentName”: “widget2”,

“isDefault”: true,

“scheduledUpdateTime”: “10:30”,//定點(diǎn)刷新的時(shí)刻,采用24小時(shí)制,精確到分鐘?!皍pdateDuration”: 0時(shí),才會(huì)生效。

“defaultDimension”: “1*2”,

“name”: “widget2”,

“description”: “This is a service widget”,

“colorMode”: “auto”,

“type”: “JS”,

“supportDimensions”: [

“1*2”

],

“updateEnabled”: true, //表示卡片是否支持周期性刷新

“updateDuration”: 1 //卡片定時(shí)刷新的更新周期,1為30分鐘,2為60分鐘,N為30*N分鐘

}

這樣結(jié)合我們?cè)谏弦徊将@取 API 數(shù)據(jù),解析 JSON,開(kāi)啟服務(wù)卡片的周期性更新,就可以在 updateFormData() 實(shí)現(xiàn)服務(wù)卡片的數(shù)據(jù)更新了。

截取 follower 數(shù)據(jù)更新的部分代碼如下:

public void updateFormData(long formId, Object.。。 vars) {

HiLog.info(TAG, “update form data: formId” + formId);

//這部分用來(lái)獲取粉絲數(shù)

String url = “https://api.bilibili.com/x/relation/stat?vmid=383565952”;

ZZRHttp.get(url, new ZZRCallBack.CallBackString() {

@Override

public void onFailure(int i, String s) {HiLog.info(TAG, “API返回失敗”);}

@Override

public void onResponse(String s) {

HiLog.info(TAG, “API返回成功”);

try {

//1.調(diào)用fastjson解析,結(jié)果保存在JSON對(duì)應(yīng)的類(lèi)

BilibiliFollower bilibiliFollower = JSON.parseObject(s,BilibiliFollower.class);

//2.get方法獲取解析內(nèi)容

BilibiliFollower.Data data= bilibiliFollower.getData();

System.out.println(“解析成功”+data.getFollower());

//這部分用來(lái)更新卡片信息

ZSONObject zsonObject = new ZSONObject(); //1.將要刷新的數(shù)據(jù)存放在一個(gè)ZSONObject實(shí)例中

zsonObject.put(“follower”,data.getFollower()); //2.更新數(shù)據(jù),data.getFollower()就是在API數(shù)據(jù)請(qǐng)求中獲取的粉絲數(shù)。

FormBindingData formBindingData = new FormBindingData(zsonObject); //3.將其封裝在一個(gè)FormBindingData的實(shí)例中

try {

((MainAbility)context).updateForm(formId,formBindingData); //4.調(diào)用MainAbility的方法updateForm(),并將formBindingData作為第二個(gè)實(shí)參

} catch (FormException e) {

e.printStackTrace();

HiLog.info(TAG, “更新卡片失敗”);

}

} catch (Exception e) {

HiLog.info(TAG, “解析失敗”);

}

}

});

}

②手動(dòng)更新

正常來(lái)說(shuō)這樣就可以正常更新數(shù)據(jù)了,但是會(huì)有個(gè)問(wèn)題。就是在服務(wù)卡片首次創(chuàng)建添加到桌面的時(shí)候,在添加完的至少 30 分鐘里,數(shù)據(jù)是不會(huì)更新的。

此時(shí)如果在 index.json 中設(shè)置初始信息,那么在添加完成的前 30 分鐘數(shù)據(jù)都是寫(xiě)死在 data 中的。如果不設(shè)置初始信息那么卡片就是空白的。

所以按照前面服務(wù)卡片的運(yùn)作機(jī)制的分析,我們還需要在卡片初始化 onCreateForm() 的時(shí)候進(jìn)行一次更新。

這個(gè)非常簡(jiǎn)單用 onCreateForm() 調(diào)用 onUpdateForm(formId) 即可。

@Overrideprotected ProviderFormInfo onCreateForm(Intent intent) {

。。。 。。。

//初始化時(shí)先在線更新一下卡片

onUpdateForm(formId);

return formController.bindFormData();

}

總結(jié):這里的 onUpdateForm(formId) 中 API 的網(wǎng)絡(luò)請(qǐng)求一定要新開(kāi)一個(gè)子線程,不然會(huì)影響頁(yè)面加載。

這也是前面說(shuō)的用 ZZRhttp 的原因。不過(guò)現(xiàn)在也遇到一個(gè)問(wèn)題,當(dāng)卡片數(shù)量變多時(shí),同時(shí)在線更新這么多的卡片會(huì)變得非常緩慢,這個(gè)問(wèn)題還有待解決。

功能直達(dá)

目前服務(wù)卡片僅支持 click 通用事件,事件類(lèi)型:跳轉(zhuǎn)事件(router)和消息事件(message)。

詳細(xì)說(shuō)明參考官方文檔:

https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-service-widget-syntax-hml-0000001152828575

①跳轉(zhuǎn)事件

接下來(lái)實(shí)現(xiàn)與服務(wù)卡片的交互,當(dāng)點(diǎn)擊服務(wù)卡片時(shí),會(huì)跳轉(zhuǎn)到相應(yīng)的頁(yè)面,所以這里使用跳轉(zhuǎn)事件。

以番劇更新的卡片為例:

首先我們要先添加一個(gè)要跳轉(zhuǎn)的頁(yè)面。如下圖所示添加一個(gè) Page Ability,比如:VideoSlice。

8490703c-fab5-11eb-9bcf-12bb97331649.png

新建完成之后會(huì)增加 VideoSlice 和 slice/VideoSliceSlice 兩個(gè)文件,和 base/layout/ability_bilibili_page.xml 頁(yè)面文件。

@Overridepublic void onStart(Intent intent) {

super.onStart(intent);

super.setUIContent(ResourceTable.Layout_ability_video);

Text text = (Text) findComponentById(ResourceTable.Id_text);

text.setText(“頁(yè)面跳轉(zhuǎn)中”);

// 隨機(jī)圖片數(shù)組

int[] resource = {ResourceTable.Media_36e,ResourceTable.Media_36g,ResourceTable.Media_36h,ResourceTable.Media_38p};

Component component = findComponentById(ResourceTable.Id_image);

if (component instanceof Image) {

Image image = (Image) component;

image.setPixelMap(resource[(int)(Math.random()*3)]);//隨機(jī)顯示一張圖片

}

String url = “https://m.bilibili.com”;

String param = intent.getStringParam(“params”);//從intent中獲取 跳轉(zhuǎn)事件定義的params字段的值

if(param !=null){

ZSONObject data = ZSONObject.stringToZSON(param);

url = data.getString(“url”);

}

webview(url);

}

//啟動(dòng)webviewpublic void webview(String url){

WebView webView = (WebView) findComponentById(ResourceTable.Id_webview);

webView.getWebConfig().setJavaScriptPermit(true); // 如果網(wǎng)頁(yè)需要使用JavaScript,增加此行;如何使用JavaScript下文有詳細(xì)介紹

webView.load(url);

}

增加 webview,將頁(yè)面默認(rèn)的 Text 控件修改為 webview。

《?xml version=“1.0” encoding=“utf-8”?》《DirectionalLayout

xmlns:ohos=“http://schemas.huawei.com/res/ohos”

ohos:height=“match_parent”

ohos:width=“match_parent”

ohos:alignment=“center”

ohos:orientation=“vertical”》

《ohos.agp.components.webengine.WebView

ohos:id=“$+id:webview”

ohos:height=“match_parent”

ohos:width=“match_parent”》

《/ohos.agp.components.webengine.WebView》《/DirectionalLayout》

在 index.hml 中給要觸發(fā)的控件上添加 onclick,比如:onclick=“routerEvent1”。

《div class=“div_root” 》《!--在服務(wù)卡片設(shè)置一個(gè) 根div 橫向布局--》

《div class=“div_container”》《!--在根div 橫向放置4個(gè)div,每個(gè)div內(nèi)部從上往下排列--》

《image class=“item_image” src=“{{ src1 }}” onclick=“routerEvent1”》《/image》

《text class=“item_title”》{{ itemTitle1 }}《/text》

《text class=“item_content”》{{ itemContent1 }}《/text》

《/div》

。。。 。。。

《/div》

在 index.json 中,添加對(duì)應(yīng)的 actions,跳轉(zhuǎn)事件要多加一個(gè)參數(shù)“abilityName”,指定要跳轉(zhuǎn)的頁(yè)面,并且攜帶參數(shù) url。

{

“data”: {

},

“actions”: {

“routerEvent1”: {

“action”: “router”,

“bundleName”: “com.liangzili.servicewidget”,

“abilityName”: “com.liangzili.servicewidget.VideoSlice”,

“params”: {

“url”: “{{url1}}”

}

},

“routerEvent2”: {

。。。 。。。

}

②消息事件

這里使用視頻動(dòng)態(tài)服務(wù)卡片,做一個(gè)消息事件的測(cè)試,效果如下圖,點(diǎn)擊左右邊,實(shí)現(xiàn)服務(wù)卡片的滑動(dòng)。

在小卡片上這樣的操作體驗(yàn)不好。所以消息事件中的例子,只是為了測(cè)試,并沒(méi)有加到項(xiàng)目里。

在 index.hml 中給要觸發(fā)的控件上添加 onclick,比如:onclick=“sendMessageEvent”。

《-- 為了方便測(cè)試,直接將onclick添加在左右兩側(cè)的div組件上 --》《div class=“div” onclick=“sendMessageEvent0”》

《image class=“item_image” src=“{{ src0 }}”》《/image》

《text class=“item_title”》{{ itemTitle0 }}《/text》

《text class=“item_content”》{{ itemContent0 }}《/text》《/div》《div class=“div” onclick=“sendMessageEvent1”》

《image class=“item_image” src=“{{ src1 }}”》《/image》

《text class=“item_title”》{{ itemTitle1 }}《/text》

《text class=“item_content”》{{ itemContent1 }}《/text》《/div》

在 index.json 中,添加對(duì)應(yīng)的 actions。

{

“data”: {

},

“actions”: {

“sendMessageEvent0”: {

“action”: “message”,

“params”: {

“p1”: “l(fā)eft”,

“index”: “{{index}}”

}

},

“sendMessageEvent1”: {

“action”: “message”,

“params”: {

“p1”: “right”,

“index”: “{{index}}”

}

}

}

}

如果是消息事件(message)當(dāng)點(diǎn)擊帶有 onclick 的控件時(shí),會(huì)觸發(fā) MainAbility 下的這個(gè)函數(shù)。

@Overrideprotected void onTriggerFormEvent(long formId, String message) {

HiLog.info(TAG, “onTriggerFormEvent: ” + message); //params的內(nèi)容就通過(guò)message傳遞過(guò)來(lái)

super.onTriggerFormEvent(formId, message);

FormControllerManager formControllerManager = FormControllerManager.getInstance(this);

FormController formController = formControllerManager.getController(formId);//通過(guò)formId得到卡片控制器

formController.onTriggerFormEvent(formId, message);//接著再調(diào)用,對(duì)應(yīng)的控制器 WidgetImpl

}

最后調(diào)用卡片控制器 WidgetImpl 中的 onTriggerFormEvent()。

public void onTriggerFormEvent(long formId, String message) {

HiLog.info(TAG, “onTriggerFormEvent.”+message);

//先獲取message中的參數(shù)

ZSONObject data = ZSONObject.stringToZSON(message);

String p1 = data.getString(“p1”);

Integer index = data.getIntValue(“index”);

ZSONObject zsonObject = new ZSONObject(); //將要刷新的數(shù)據(jù)存放在一個(gè)ZSONObject實(shí)例中

Integer indexMax = 2; //有N個(gè)滑塊組件就設(shè)置N-1

if(p1.equals(“right”)){ //判斷點(diǎn)擊方向,如果是右側(cè)

if(index == indexMax){index = -1;} //實(shí)現(xiàn)循環(huán)滾動(dòng)

index = index+1;

zsonObject.put(“index”,index);

}else { //判斷點(diǎn)擊方向,如果是左側(cè)

if(index == 0){index = indexMax+1;} //實(shí)現(xiàn)循環(huán)滾動(dòng)

index = index-1;

zsonObject.put(“index”,index);

}

FormBindingData formBindingData = new FormBindingData(zsonObject);

try {

((MainAbility)context).updateForm(formId,formBindingData);

} catch (FormException e) {

e.printStackTrace();

HiLog.info(TAG, “更新卡片失敗”);

}

}

③list 跳轉(zhuǎn)事件

list 組件只能添加一個(gè) onclick,而且在點(diǎn)擊的同時(shí)還需要獲取點(diǎn)擊的是list列表中的哪一項(xiàng),這個(gè)比較特殊。

《list class=“l(fā)ist” else》

《list-item for=“{{list}}” class=“l(fā)ist-item”》

《div class=“div” onclick=“sendRouteEvent”》

。。。 。。。

《/div》

《/list-item》

《/list》

這個(gè)坑折磨了我好久,最終我發(fā)現(xiàn)在 index.json 中,可以使用 item,item,idx 獲取到 hml 頁(yè)面 list 的元素變量和索引。

但是在官方文檔并沒(méi)有找到相關(guān)的內(nèi)容,嘗試了很久才解決這個(gè)問(wèn)題。之后的部分就和跳轉(zhuǎn)事件一樣了,使用 Video 頁(yè)面解析 url 進(jìn)行播放就可以了。

“actions”: {

“sendRouteEvent”: {

“action”: “router”,

“bundleName”: “com.liangzili.demos”,

“abilityName”: “com.liangzili.demos.Video”,

“params”: {

“url”: “{{$item.short_url}}”,

“index”: “{{$idx}}”

}

}

}

總結(jié):解決了 list 的點(diǎn)擊事件之后,才發(fā)現(xiàn)這歌控件真是好用。能用 list 還是 list 方便。

加載頁(yè)面,保存 Cookie

啟動(dòng)之后的頁(yè)面主要是為了登錄賬號(hào),因?yàn)榇蟛糠值?API 是需要登錄之后才可以獲取到的。

①webview 加載頁(yè)面

在 base/layout/ability_main.xml 中添加 webview 組件,代碼如下:

《ohos.agp.components.webengine.WebView

ohos:id=“$+id:webview”

ohos:height=“match_parent”

ohos:width=“match_parent”》

《/ohos.agp.components.webengine.WebView》

然后在啟動(dòng)頁(yè)面執(zhí)行加載操作。但其實(shí)加載前需要先從數(shù)據(jù)庫(kù)中提取 cookie 信息,這個(gè)接下來(lái)說(shuō)。

String url = “https://m.bilibili.com”;

WebView webView = (WebView) findComponentById(ResourceTable.Id_webview);

webView.getWebConfig().setJavaScriptPermit(true); // 如果網(wǎng)頁(yè)需要使用JavaScript,增加此行;如何使用JavaScript下文有詳細(xì)介紹

webView.load(url);

②Cookie 的讀取和保存類(lèi)

com/liangzili/demos/utils/CookieUtils.java:

public class CookieUtils {

private static final HiLogLabel TAG = new HiLogLabel(HiLog.DEBUG,0x0,CookieUtils.class.getName());

/**

* 使用關(guān)系型數(shù)據(jù)庫(kù)[讀?。軨ookie

* @param preferences

* @param url

*/

public static void ExtarctCookie(Preferences preferences, String url){

Map《String, ?》 map = new HashMap《》();

//先從數(shù)據(jù)庫(kù)中取出cookie

map = PreferenceDataBase.GetCookieMap(preferences);

//然后寫(xiě)入到cookieStore

CookieStore cookieStore = CookieStore.getInstance();//1.獲取一個(gè)CookieStore的示例

for (Map.Entry《String, ?》 entry : map.entrySet()) {

HiLog.info(TAG,entry.getKey()+“=”+entry.getValue().toString());

cookieStore.setCookie(url,entry.getKey()+“=”+entry.getValue().toString());//2.寫(xiě)入數(shù)據(jù),只能一條一條寫(xiě)

}

}

/**

* 使用關(guān)系型數(shù)據(jù)庫(kù)[保存]Cookie

* @param preferences 數(shù)據(jù)庫(kù)的Preferences實(shí)例

* @param url 指定Cookie對(duì)應(yīng)的域名

*/

public static void SaveCookie(Preferences preferences,String url){

//先取出要保存的cookie

CookieStore cookieStore = CookieStore.getInstance();

String cookieStr = cookieStore.getCookie(url);

HiLog.info(TAG,“saveCookie(String url)”+url+cookieStr);

//然后將cooke轉(zhuǎn)成map

Map《String,String》 cookieMap = cookieToMap(cookieStr);

//最后將map寫(xiě)入數(shù)據(jù)庫(kù)

PreferenceDataBase.SaveMap(preferences,cookieMap);

}

// cookieToMap

public static Map《String,String》 cookieToMap(String value) {

Map《String, String》 map = new HashMap《String, String》();

value = value.replace(“ ”, “”);

if (value.contains(“;”)) {

String values[] = value.split(“;”);

for (String val : values) {

String vals[] = val.split(“=”);

map.put(vals[0], vals[1]);

}

} else {

String values[] = value.split(“=”);

map.put(values[0], values[1]);

}

return map;

}

}

偏好型數(shù)據(jù)庫(kù)

數(shù)據(jù)庫(kù)的操作主要是 com/liangzili/demos/database/PreferenceDataBase.java 這個(gè)類(lèi)。使用輕量級(jí)偏好型數(shù)據(jù)庫(kù),更符合我們這里的需求。

①獲取 Preferences 實(shí)例

public class PreferenceDataBase {

private static final HiLogLabel TAG = new HiLogLabel(HiLog.DEBUG,0x0,PreferenceDataBase.class.getName());

/**

* 獲取Preferences實(shí)例

* @param context 數(shù)據(jù)庫(kù)文件將存儲(chǔ)在由context上下文指定的目錄里。

* @param name fileName表示文件名,其取值不能為空,也不能包含路徑

* @return //返回對(duì)應(yīng)數(shù)據(jù)庫(kù)的Preferences實(shí)例

*/

public static Preferences register(Context context,String name) {

DatabaseHelper databaseHelper = new DatabaseHelper(context);

Preferences preferences = databaseHelper.getPreferences(name);

return preferences;

}

。。。 。。。

}

②從數(shù)據(jù)庫(kù)中保存和讀取 Map

/**

* Map[保存]到偏好型數(shù)據(jù)庫(kù)

* @param preferences 數(shù)據(jù)庫(kù)的Preferences實(shí)例

* @param map 要保存的map

*/

public static void SaveMap(Preferences preferences,Map《String,String》 map){

// 遍歷map

for (Map.Entry《String, String》 entry : map.entrySet()) {

HiLog.info(TAG,entry.getKey() + “=” + entry.getValue());

preferences.putString(entry.getKey(),entry.getValue());//3.將數(shù)據(jù)寫(xiě)入Preferences實(shí)例,

}

preferences.flushSync();//4.通過(guò)flush()或者flushSync()將Preferences實(shí)例持久化。

}

/**

* 從偏好型數(shù)據(jù)庫(kù)[讀取]Map

* @param preferences 數(shù)據(jù)庫(kù)的Preferences實(shí)例

* @return 要讀取的map

*/

public static Map《String,?》 GetCookieMap(Preferences preferences){

Map《String, ?》 map = new HashMap《》();

map = preferences.getAll();//3.讀取數(shù)據(jù)

return map;

}

③提取某些 Cookie 的值

/**

* 獲取Cookie中的SESSDATA值

* @param context 上下文用來(lái)指定數(shù)據(jù)文件存儲(chǔ)路徑

* @return Cookie中的SESSDATA值

*/

public static String getSessData(Context context){

// 開(kāi)啟數(shù)據(jù)庫(kù)

DatabaseHelper databaseHelper = new DatabaseHelper(context);//1.創(chuàng)建數(shù)據(jù)庫(kù)使用數(shù)據(jù)庫(kù)操作的輔助類(lèi)

Preferences preferences = databaseHelper.getPreferences(“bilibili”);//2.獲取到對(duì)應(yīng)文件名的Preferences實(shí)例,filename是String類(lèi)型

String SESSDATA = preferences.getString(“SESSDATA”,“”); //3.讀取數(shù)據(jù)

return SESSDATA;

}

/**

* 獲取Cookie中的Vmid值

* @param context

* @return Cookie中的Vmid值

*/

public static String getVmid(Context context){

// 開(kāi)啟數(shù)據(jù)庫(kù)

DatabaseHelper databaseHelper = new DatabaseHelper(context);//1.創(chuàng)建數(shù)據(jù)庫(kù)使用數(shù)據(jù)庫(kù)操作的輔助類(lèi)

Preferences preferences = databaseHelper.getPreferences(“bilibili”);//2.獲取到對(duì)應(yīng)文件名的Preferences實(shí)例,filename是String類(lèi)型

String DedeUserID = preferences.getString(“DedeUserID”,“”); //3.讀取數(shù)據(jù)

return DedeUserID;

}

編輯:jq

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    7035

    瀏覽量

    89047
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4788

    瀏覽量

    68628
  • 鴻蒙
    +關(guān)注

    關(guān)注

    57

    文章

    2352

    瀏覽量

    42863

原文標(biāo)題:我為B站添加鴻蒙服務(wù)卡片!

文章出處:【微信號(hào):Huawei_Kirin,微信公眾號(hào):華為麒麟】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    鴻蒙原生開(kāi)發(fā)手記:02-服務(wù)卡片開(kāi)發(fā)

    介紹 服務(wù)卡片是一直桌面小組件,可以放置在桌面上等位置,一觸即達(dá)。 服務(wù)卡片分為靜態(tài)卡片和動(dòng)態(tài)卡片
    發(fā)表于 11-14 17:48

    鴻蒙原生開(kāi)發(fā)手記:01-元服務(wù)開(kāi)發(fā)

    同樣的使用方法。 服務(wù)卡片服務(wù)可以添加服務(wù)卡片,詳細(xì)介紹見(jiàn)《
    發(fā)表于 11-14 17:28

    HarmonyOS NEXT應(yīng)用元服務(wù)開(kāi)發(fā)Intents Kit(意圖框架服務(wù))本地搜索方案概述

    用戶(hù)感興趣的歌曲,那么后續(xù)用戶(hù)在小藝搜索入口中搜索歌名時(shí),系統(tǒng)將會(huì)在應(yīng)用/元服務(wù)共享的數(shù)據(jù)中檢索對(duì)應(yīng)內(nèi)容,并使用卡片的形式展示內(nèi)容結(jié)果,當(dāng)用戶(hù)點(diǎn)擊對(duì)應(yīng)卡片熱區(qū)時(shí),可以跳轉(zhuǎn)進(jìn)具體音樂(lè)播放頁(yè)或者直接后臺(tái)執(zhí)行
    發(fā)表于 11-06 10:59

    HarmonyOS Next元服務(wù)開(kāi)發(fā)快速入門(mén)案例

    ;base>media下添加圖片 二、創(chuàng)建卡片widget 1.創(chuàng)建微、小、中、大卡片 2.依次創(chuàng)建卡片 3.卡片創(chuàng)建完成,修改
    發(fā)表于 10-08 10:51

    基于鴻蒙Next模擬卡片數(shù)據(jù)數(shù)據(jù)更新

    一、介紹 基于鴻蒙Next模擬卡片數(shù)據(jù)數(shù)據(jù)更新二、場(chǎng)景需求 電商平臺(tái)產(chǎn)品信息更新、 客戶(hù)關(guān)系管理(CRM)系統(tǒng)、 社交媒體用戶(hù)資料更新、 健康管理系統(tǒng)、 項(xiàng)目管理工具、 金融服務(wù)應(yīng)用、 教育管理系統(tǒng)
    發(fā)表于 08-30 15:32

    服務(wù)體驗(yàn)-服務(wù)管理與分享

    服務(wù)管理 通過(guò)桌面、負(fù)一屏、應(yīng)用市場(chǎng)、元服務(wù)等場(chǎng)景對(duì)元服務(wù)進(jìn)行添加、收藏、移除等管理操作。 服務(wù)分享 元
    發(fā)表于 07-16 15:43

    OpenHarmony開(kāi)發(fā)案例:【電影卡片

    基于元服務(wù)卡片的能力,實(shí)現(xiàn)帶有卡片的電影應(yīng)用,介紹卡片的開(kāi)發(fā)過(guò)程和生命周期實(shí)現(xiàn)。
    的頭像 發(fā)表于 04-15 17:53 ?1267次閱讀
    OpenHarmony開(kāi)發(fā)案例:【電影<b class='flag-5'>卡片</b>】

    B熱門(mén)手游《碧藍(lán)航線》將接入鴻蒙系統(tǒng),華為已超4000個(gè)應(yīng)用完成遷移

    在此之前,B已經(jīng)宣布將在鴻蒙領(lǐng)域展開(kāi)全方位合作。此次嗶哩嗶哩游戲宣布將《碧藍(lán)航線》納入鴻蒙原生應(yīng)用開(kāi)發(fā)項(xiàng)目,標(biāo)志著其與華為游戲中心在產(chǎn)品應(yīng)用方面的深入探索。
    的頭像 發(fā)表于 04-12 10:25 ?783次閱讀

    鴻蒙OS開(kāi)發(fā)案例:【Stage模型卡片

    本示例展示了Stage模型卡片提供方的創(chuàng)建與使用。
    的頭像 發(fā)表于 04-09 17:13 ?995次閱讀
    <b class='flag-5'>鴻蒙</b>OS開(kāi)發(fā)案例:【Stage模型<b class='flag-5'>卡片</b>】

    鴻蒙OS實(shí)戰(zhàn)開(kāi)發(fā):【多設(shè)備自適應(yīng)服務(wù)卡片

    服務(wù)卡片的布局和使用,其中卡片內(nèi)容顯示使用了一次開(kāi)發(fā),多端部署的能力實(shí)現(xiàn)多設(shè)備自適應(yīng)。 用到了卡片擴(kuò)展模塊接口,[@ohos.app.form.FormExtensionAbil
    的頭像 發(fā)表于 04-09 09:20 ?863次閱讀
    <b class='flag-5'>鴻蒙</b>OS實(shí)戰(zhàn)開(kāi)發(fā):【多設(shè)備自適應(yīng)<b class='flag-5'>服務(wù)</b><b class='flag-5'>卡片</b>】

    B完成鴻蒙原生應(yīng)用Beta版研發(fā)

    此外,用戶(hù)還可在該平臺(tái)上即時(shí)參與一鍵三連、發(fā)表彈幕和評(píng)論等多元化的社區(qū)活動(dòng)。B官方承諾,接下來(lái)會(huì)進(jìn)一步優(yōu)化視頻消費(fèi)及社交互動(dòng)功能,并在鴻蒙系統(tǒng)自帶的智能、安全和連接功能基礎(chǔ)上,帶給大家更多創(chuàng)新體驗(yàn),如內(nèi)容智能流轉(zhuǎn)、版面智能布置
    的頭像 發(fā)表于 03-29 16:20 ?720次閱讀

    鴻蒙OS開(kāi)發(fā)實(shí)例:【手?jǐn)]服務(wù)卡片

    服務(wù)卡片指導(dǎo)文檔位于“**開(kāi)發(fā)/應(yīng)用模型/Stage模型開(kāi)發(fā)指導(dǎo)/Stage模型應(yīng)用組件**”路徑下,說(shuō)明其極其重要。本篇文章將分享實(shí)現(xiàn)服務(wù)卡片的過(guò)程和代碼
    的頭像 發(fā)表于 03-28 22:11 ?1209次閱讀
    <b class='flag-5'>鴻蒙</b>OS開(kāi)發(fā)實(shí)例:【手?jǐn)]<b class='flag-5'>服務(wù)</b><b class='flag-5'>卡片</b>】

    鴻蒙實(shí)戰(zhàn)項(xiàng)目開(kāi)發(fā):【短信服務(wù)

    數(shù)據(jù)管理 電話服務(wù) 分布式應(yīng)用開(kāi)發(fā) 通知與窗口管理 多媒體技術(shù) 安全技能 任務(wù)管理 WebGL 國(guó)際化開(kāi)發(fā) 應(yīng)用測(cè)試 DFX面向未來(lái)設(shè)計(jì) 鴻蒙系統(tǒng)移植和裁剪定制 …… ? 《鴻蒙開(kāi)發(fā)實(shí)戰(zhàn)》 ArkTS實(shí)踐
    發(fā)表于 03-03 21:29

    潤(rùn)開(kāi)鴻發(fā)布“鴻通學(xué)”品牌及企業(yè)鴻蒙原生應(yīng)用一式賦能及開(kāi)發(fā)服務(wù)

    1月25日,“鴻蒙千帆起,學(xué)鴻正當(dāng)時(shí)”鴻通學(xué)·企業(yè)鴻蒙原生應(yīng)用一式賦能及開(kāi)發(fā)服務(wù)(以下簡(jiǎn)稱(chēng)“鴻通學(xué)”)線上發(fā)布會(huì)圓滿召開(kāi)。江蘇潤(rùn)開(kāi)鴻數(shù)字科技有限公司(以下簡(jiǎn)稱(chēng)“潤(rùn)開(kāi)鴻”)正式推出面向
    的頭像 發(fā)表于 01-26 14:48 ?457次閱讀
    潤(rùn)開(kāi)鴻發(fā)布“鴻通學(xué)”品牌及企業(yè)<b class='flag-5'>鴻蒙</b>原生應(yīng)用一<b class='flag-5'>站</b>式賦能及開(kāi)發(fā)<b class='flag-5'>服務(wù)</b>

    鴻蒙HarmonyOS元服務(wù)-“文學(xué)素養(yǎng)”說(shuō)明

    1.概述 文學(xué)素養(yǎng)將中華傳統(tǒng)文化中的常用漢字解釋?zhuān)瑑?yōu)秀的經(jīng)、文、楚辭、漢賦、唐詩(shī)、宋詞、原曲、明清小說(shuō),多音字,生僻字,成語(yǔ)測(cè)試等和HarmonyOS具備的元服務(wù)、萬(wàn)能卡片能力進(jìn)行融合,嘗試用一種
    發(fā)表于 01-10 10:11