鸿蒙网络编程系列63-仓颉版web组件与应用互操作示例

1. APP内嵌网页与应用互操作概述

在APP应用开发中,通过内嵌网页的形式可以很方便的适配多种系统平台,提高开发效率,而且,网页具有即时加载的特点,减少了更新APP版本的次数和要求。更重要的是,可以通过应用和网页的互操作来提升用户的使用体验,也就是可以在网页中调用APP中的方法,或者在APP中执行网页中的脚本,鸿蒙通过仓颉WebviewController类中的registerJavaScriptProxy接口提供了注册应用侧函数到web组件中的方法;如果要在应用侧执行网页中的脚本使用的是runJavaScript接口。

在本系列的第24篇文章《鸿蒙网络编程系列24-Web组件与应用互操作示例》中介绍了如何在API12环境下使用ArkTS语言执行网页与应用的互操作;本篇文章将在API 17环境下,使用仓颉语言实现类似的功能。

2. APP内嵌网页与应用互操作示例演示

本示例运行后的界面如图所示:

拖动RGB颜色分量,可以选择合适的颜色,然后单击“设置网页背景色”按钮,即可在应用侧调用网页中的脚本函数设置网页背景色,如图所示:

也可以输入乘数和被乘数,然后单击网页中的“计算应用侧的乘法”按钮,在网页中调用应用侧的函数,如图所示:

3. APP内嵌网页与应用互操作示例编写

下面详细介绍创建该示例的步骤(确保DevEco Studio已安装仓颉插件)。

步骤1:创建[Cangjie]Empty Ability项目。

步骤2:在module.json5配置文件加上对权限的声明:

"requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]

这里添加了访问互联网的权限。

步骤3:在build-profile.json5配置文件加上仓颉编译架构:

"cangjieOptions": {
      "path": "./src/main/cangjie/cjpm.toml",
      "abiFilters": ["arm64-v8a", "x86_64"]
    }

步骤4:在main_ability.cj文件里添加如下的代码:

package ohos_app_cangjie_entry

internal import ohos.base.AppLog
internal import ohos.ability.AbilityStage
internal import ohos.ability.LaunchReason
internal import cj_res_entry.app
import ohos.ability.*

//Ability全局上下文
var globalAbilityContext: Option<AbilityContext> = Option<AbilityContext>.None
class MainAbility <: Ability {
    public init() {
        super()
        registerSelf()
    }

    public override func onCreate(want: Want, launchParam: LaunchParam): Unit {
        AppLog.info("MainAbility OnCreated.${want.abilityName}")
        globalAbilityContext = Option<AbilityContext>.Some(this.context)
        match (launchParam.launchReason) {
            case LaunchReason.START_ABILITY => AppLog.info("START_ABILITY")
            case _ => ()
        }
    }

    public override func onWindowStageCreate(windowStage: WindowStage): Unit {
        AppLog.info("MainAbility onWindowStageCreate.")
        windowStage.loadContent("EntryView")
    }
}

步骤5:在index.cj文件里添加如下的代码:

package ohos_app_cangjie_entry

internal import ohos.base.*
internal import ohos.component.*
import ohos.state_manage.*
import ohos.state_macro_manage.*
import ohos.webview.*
import std.convert.*
import std.format.*

//注册到web组件中的应用侧对象
@Observed
class ComputeObj {
    public var multiplier: Float64 = 0.618
    public var multiplicand: Float64 = 3.14
    @Publish
    public var product: String = "乘积"

    //获取乘数
    public func getMultiplier() {
        return this.multiplier;
    }

    //获取被乘数
    public func getMultiplicand() {
        return this.multiplicand;
    }

    //设置乘积
    public func setProduct(newProduct: String) {
        this.product = newProduct
    }
}

//调用js函数的回调
let callback: AsyncCallback<String> = {
    errorCode: Option<AsyncError>, data: Option<String> => match (errorCode) {
        case Some(e) => AppLog.error("回调出错:错误码为 ${e.code}")
        case _ => match (data) {
            case Some(value) => AppLog.info("回调: 成功获取数据:${value}")
            case _ => AppLog.error("回调出错: 数据为空")
        }
    }
}

@Entry
@Component
class EntryView {
    @State
    var title: String = "Web组件与应用互操作示例"
    @State
    var computeObj: ComputeObj = ComputeObj()
    let jsName: String = "multipObj"
    @State
    var rColor: UInt8 = 100
    @State
    var gColor: UInt8 = 100
    @State
    var bColor: UInt8 = 100
    @State
    var backColor: String = "#646464"

    //是否已注册仓颉函数
    var isCJfuncReg: Bool = false

    let scroller: Scroller = Scroller()
    let webController: WebviewController = WebviewController()

    func build() {
        Row {
            Column {
                Text(title)
                    .fontSize(14)
                    .fontWeight(FontWeight.Bold)
                    .width(100.percent)
                    .textAlign(TextAlign.Center)
                    .padding(10)

                Text("输入乘数和被乘数,在web组件中单击计算按钮进行计算")
                    .fontSize(14)
                    .fontWeight(FontWeight.Bold)
                    .width(100.percent)
                    .textAlign(TextAlign.Center)
                    .padding(10)

                Flex(FlexParams(justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center)) {
                    TextInput(text: this.computeObj.multiplier.format(".3"))
                        .onChange({
                            value => this.computeObj.multiplier = Float64.parse(value)
                        })
                        .width(100)
                        .fontSize(11)
                        .flexGrow(1)

                    Text("*").fontSize(14).width(20)
                    TextInput(text: this.computeObj.multiplicand.format(".3"))
                        .onChange({
                            value => this.computeObj.multiplicand = Float64.parse(value)
                        })
                        .width(100)
                        .fontSize(11)
                        .flexGrow(1)
                    Text("=").fontSize(14).width(20)

                    TextInput(text: this.computeObj.product).width(100).fontSize(11).flexGrow(1).enabled(false)
                }.width(100.percent).padding(10)

                Flex(FlexParams(justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center)) {
                    Text("R颜色分量").fontSize(14).width(100)

                    Slider(value: Float64(this.rColor), min: 0.0, max: 255.0).onChange(
                        {
                            value: Float64, mode: SliderChangeMode =>
                            this.rColor = UInt8(value)
                            this.computeBackcolor()
                        }
                    )
                }.width(100.percent).padding(10)

                Flex(FlexParams(justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center)) {
                    Text("G颜色分量").fontSize(14).width(100)

                    Slider(value: Float64(this.gColor), min: 0.0, max: 255.0).onChange(
                        {
                            value: Float64, mode: SliderChangeMode =>
                            this.gColor = UInt8(value)
                            this.computeBackcolor()
                        }
                    )
                }.width(100.percent).padding(10)

                Flex(FlexParams(justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center)) {
                    Text("B颜色分量").fontSize(14).width(100)

                    Slider(value: Float64(this.bColor), min: 0.0, max: 255.0).onChange(
                        {
                            value: Float64, mode: SliderChangeMode =>
                            this.bColor = UInt8(value)
                            this.computeBackcolor()
                        }
                    )
                }.width(100.percent).padding(10)

                Flex(FlexParams(justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center)) {
                    Text("选中的颜色:" + this.backColor)
                        .fontSize(14)
                        .width(100)
                        .backgroundColor(Color(this.rColor, this.gColor, this.bColor))

                    Button("设置网页背景色").onClick(
                        {
                            => this.webController.runJavaScript("setbackcolor('" + this.backColor + "')", callback)
                        })
                }.width(100.percent).padding(10)
                Scroll(scroller) {
                    Web(src: @rawfile("demo.html"), controller: webController)
                        .domStorageAccess(true)
                        .fileAccess(true)
                        .padding(10)
                        .width(100.percent)
                        .backgroundColor(0xeeeeee)
                        .onAppear({
                            => if (!this.isCJfuncReg) {
                                isCJfuncReg = true
                                regCjMethods()
                                webController.refresh()
                            }
                        })
                }
                    .align(Alignment.Top)
                    .backgroundColor(0xeeeeee)
                    .height(300)
                    .flexGrow(1)
                    .scrollable(ScrollDirection.Vertical)
                    .scrollBar(BarState.On)
                    .scrollBarWidth(20)
            }.width(100.percent).height(100.percent)
        }.height(100.percent)
    }

    //注册仓颉函数
    func regCjMethods() {
        let getMultiplier = {
            p: String => return computeObj.getMultiplier().toString()
        }

        let getMultiplicand = {
            p: String => return computeObj.getMultiplicand().toString()
        }

        let setProduct = {
            p: String =>
            computeObj.setProduct(p)
            return ""
        }
        let funcsList = Array<(String) -> String>([getMultiplier, getMultiplicand, setProduct])

        let methodList = Array<String>(["getMultiplier", "getMultiplicand", "setProduct"])

        webController.registerJavaScriptProxy(funcsList, jsName, methodList)
    }
    //计算背景色
    func computeBackcolor() {
        this.backColor = "#" + this.rColor.format(".2X") + this.gColor.format(".2X") + this.bColor.format(".2X")
    }
}

步骤6:添加资源文件demo.html,路径为src/main/resources/rawfile/demo.html,内容如下:

<!-- index.html -->
<!DOCTYPE html>
<html>
<meta charset="utf-8">

<body>
<div style="text-align: center;">
    <button style="font-size: 30px;" type="button" onclick="compute()">计算应用侧的乘法</button>
</div>
<div id="info">

</div>
</body>
<script type="text/javascript">
    function compute() {
      let multiplier = multipObj.getMultiplier("");
      let multiplicand = multipObj.getMultiplicand("");
      let product = Number(multiplier) * Number(multiplicand)
      multipObj.setProduct(product.toFixed(3));
    }

    function setbackcolor(color) {
      document.body.style.backgroundColor = color;
    }
</script>

</html>

步骤7:编译运行,可以使用模拟器或者真机。

步骤8:按照本文第2部分“APP内嵌网页与应用互操作示例演示”操作即可。

4. 代码分析

要成功运行本示例,需要保证应用和网页中相关函数的一致性,第一个是在应用中调用脚本的函数设置背景色,在脚本中该函数叫setbackcolor,那么,在应用中调用该函数的代码如下:

   Button("设置网页背景色").onClick(
                        {
                            => this.webController.runJavaScript("setbackcolor('" + this.backColor + "')", callback)
                        })

只有保证两个函数名称及签名一致才能调用成功;

第二个是在网页中调用应用侧的函数,相关注册函数到web组件的代码如下:

    func regCjMethods() {
        let getMultiplier = {
            p: String => return computeObj.getMultiplier().toString()
        }

        let getMultiplicand = {
            p: String => return computeObj.getMultiplicand().toString()
        }

        let setProduct = {
            p: String =>
            computeObj.setProduct(p)
            return ""
        }
        let funcsList = Array<(String) -> String>([getMultiplier, getMultiplicand, setProduct])

        let methodList = Array<String>(["getMultiplier", "getMultiplicand", "setProduct"])

        webController.registerJavaScriptProxy(funcsList, jsName, methodList)
    }

可以看到,仓颉中的三个函数分别叫做getMultiplier、getMultiplicand和setProduct,然后放入到数组funcsList中,这三个函数注册到web组件中的函数名称也分别叫做getMultiplier、getMultiplicand和setProduct,然后放入到数组methodList中,需要说明的是,funcsList和methodList中对应的函数名称可以不一样,但是,在methodList中的名称必须和demoh.html脚本中调用的函数名称一致。

(本文作者原创,除非明确授权禁止转载)

本文源码地址:
https://gitee.com/zl3624/harmonyos_network_samples/tree/master/code/web/WebAppInteropDemo4Cj

本系列源码地址:
https://gitee.com/zl3624/harmonyos_network_samples

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值