​【关键字】

HarmonyOS、H5页面、拨打电话、获取系统定位、跳转高德地图导航

【1、写在前面】

上一篇中我们带领大家实现了一个在低码项目中跳转加载H5页面的功能,有兴趣的可以参考以下文章:

https://developer.huawei.com/consumer/cn/forum/topic/0208121373041025092?fid=0102683795438680754

今天我们继续在上一篇的基础上继续开发,这次我们要实现的功能是在H5页面中点击按钮实现:①拨打电话、②获取系统定位、③拉起第三方地图应用开启导航功能(本文以高德地图为例),本项目是基于API6的JS工程,项目中使用的是JS FA调用Java PA机制(Java中使用WebView组件加载H5页面),OK,下面一起来实战一下吧。

完整代码见文末。

【2、H5页面】

想要实现上面的效果,我们的核心技术点就是JS跟Java的数据交互,可以参考以下官方文档中的实现:

https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ui-java-component-webview-0000001092715158#section6833162911117

首先准备一个H5页面,页面内容很简单,就是3个按钮,每个按钮绑定一个点击事件,点击事件中是JS调用Java的代码,然后将该文件放在本地entry/src/main/resources/rawfile目录下,这里仅仅是简单写一个H5页面做为测试使用,实际项目开发中此部分内容可以不用看,以实际H5页面地址为准。内容如下:

​​

关于加载本地H5页面可以参考文档中的写法,文档地址如下:

https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ui-java-component-webview-0000001092715158#section1280373621914

【3、拨打电话】

前面在H5页面中已经定义了JS调用Java端的方法名及参数,这里参考文档中的写法:

https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ui-java-component-webview-0000001092715158#section6833162911117

然后在Java侧实现addJsCallback(),在回调方法onCallback中实现具体的拨打电话的业务逻辑:

【4、获取定位】

想要获取系统的位置信息,首先需要获取定位权限,关于权限的获取可以参考这篇文章中的实现:

https://ost.51cto.com/posts/5165

我们这里获取的是LOCATION权限,需要在config.json文件的module中添加权限配置,

然后需要编写动态获取权限的代码:

在获取权限之后,就可以编写获取位置信息的代码了,关于如何获取位置信息可以参考这篇文章:

https://www.51cto.com/article/679565.html

location对象中就可以获取到经纬度等位置信息了。然后同样的需要实现onCallback()方法:

【5、跳转导航】

这里我们是通过(逆)地理编码转化结合Scheme跳转来实现拉起导航功能的,(逆)地理编码转化的参考文档如下:

https://developer.harmonyos.com/cn/docs/documentation/doc-guides/device-location-geocoding-0000001053187503

高德地图导航的Scheme协议要求如下:

https://lbs.amap.com/api/amap-mobile/guide/android/navigation

跳转的代码就很简单啦:

同样的需要实现onCallback()方法:

【6、实现效果】

最后来看一下实现的效果吧:

【7、完整代码】

test.html文件:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试页面</title>
<script>
function callToApp() {
if (window.JsCallbackToCall && window.JsCallbackToCall.call) {
var result = JsCallbackToCall.call("10086");
}
}
function locationToApp() {
if (window.JsCallbackToLocation && window.JsCallbackToLocation.call) {
var result = JsCallbackToLocation.call("");
}
}
function naviToApp() {
if (window.JsCallbackToNavi && window.JsCallbackToNavi.call) {
var result = JsCallbackToNavi.call("南京市玄武湖");
}
}
</script>
</head> <body>
<div align="center">
<button type="button" id="btn_call" "callToApp()">电话</button>
<button type="button" id="btn_location" "locationToApp()">定位</button>
<button type="button" id="btn_navi" "naviToApp()">导航</button>
</div>
</body> </html>

相关文本字段strings.json中:

{
"name": "permission_location",
"value": "定位原因"
}

index.js中跳转H5Ability.java页面代码:

gotoH5Ability() {
featureAbility.startAbility({
want:
{
bundleName: "com.jarchie.h5",
abilityName: "com.jarchie.h5.H5Ability"
},
});
}

config.json中的权限配置:

"reqPermissions": [
{
"name": "ohos.permission.INTERNET"
},
{
"name": "ohos.permission.LOCATION",
"reason": "$string:permission_location",
"usedScene": {
"ability": [
"com.jarchie.h5.H5Ability"
],
"when": "always"
}
}
]

H5Ability.java:

import com.jarchie.h5.slice.H5AbilitySlice;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.agp.window.dialog.ToastDialog;
import ohos.bundle.IBundleManager; import static com.jarchie.h5.slice.LocationAbilitySlice.MY_PERMISSIONS_REQUEST_LOCATION; public class H5Ability extends Ability {
private H5AbilitySlice h5AbilitySlice; @Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setMainRoute(H5AbilitySlice.class.getName());
} @Override
public void onRequestPermissionsFromUserResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsFromUserResult(requestCode, permissions, grantResults);
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
// 匹配requestPermissions的requestCode
if (grantResults.length > 0
&& grantResults[0] == IBundleManager.PERMISSION_GRANTED) {
// 权限被授予之后做相应业务逻辑的处理
h5AbilitySlice.requestLocation();
} else {
// 权限被拒绝
new ToastDialog(getContext()).setText("权限被拒绝").show();
}
return;
}
}
} public H5AbilitySlice getH5AbilitySlice() {
return h5AbilitySlice;
} public void setH5AbilitySlice(H5AbilitySlice h5AbilitySlice) {
this.h5AbilitySlice = h5AbilitySlice;
}
}

ability_h5.xml:

<?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="horizontal_center"
ohos:orientation="vertical"> <Text
ohos:id="$+id:back"
ohos:height="50vp"
ohos:width="match_parent"
ohos:start_margin="10vp"
ohos:end_margin="10vp"
ohos:text="返回"
ohos:text_size="18vp"/> <ohos.agp.components.webengine.WebView
ohos:id="$+id:webview"
ohos:height="match_parent"
ohos:width="match_parent"/>
</DirectionalLayout>

H5AbilitySlice.java:

import com.jarchie.h5.H5Ability;
import com.jarchie.h5.ResourceTable;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Text;
import ohos.agp.components.webengine.*;
import ohos.agp.utils.TextTool;
import ohos.agp.window.dialog.ToastDialog;
import ohos.bundle.IBundleManager;
import ohos.global.resource.Resource;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.location.*;
import ohos.utils.net.Uri; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLConnection;
import java.util.List; public class H5AbilitySlice extends AbilitySlice {
private static final HiLogLabel TAG = new HiLogLabel(HiLog.DEBUG, 0x0, H5AbilitySlice.class.getName());
private Text backText;
private WebView webView;
// 定位
public static final int MY_PERMISSIONS_REQUEST_LOCATION = 0;
private Locator locator;
private RequestParam requestParam;
private MyLocatorCallback locatorCallback; @Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_h5);
H5Ability h5Ability = (H5Ability) getAbility();
h5Ability.setH5AbilitySlice(this);
initBackText();
initWebView();
callPhone();
location();
navi();
} private void navi(){
final String jsName = "JsCallbackToNavi";
webView.addJsCallback(jsName, new JsCallback() {
@Override
public String onCallback(String msg) {
gotoGaode(msg);
return "jsResult";
}
});
} // 获取定位
private void location(){
final String jsName = "JsCallbackToLocation";
webView.addJsCallback(jsName, new JsCallback() {
@Override
public String onCallback(String msg) {
requestPermission();
return "jsResult";
}
});
} // 拨打电话
private void callPhone(){
final String jsName = "JsCallbackToCall";
webView.addJsCallback(jsName, new JsCallback() {
@Override
public String onCallback(String msg) {
// 增加自定义处理
Intent intent = new Intent();
intent.setAction("ohos.intent.action.dial");
intent.setUri(Uri.parse("tel:"+msg));
startAbility(intent,0);
return "jsResult";
}
});
} private void gotoGaode(String destination){
try {
// (逆)地理编码转换
GeoConvert geoConvert = new GeoConvert();
List<GeoAddress> geoList = geoConvert.getAddressFromLocationName(destination, 1);
GeoAddress geoAddress = geoList.get(0);
if (geoAddress == null)
return;
Intent intent1 = new Intent();
Operation operation = new Intent.OperationBuilder()
.withAction("android.intent.action.VIEW")
.withUri(Uri.parse("androidamap://navi?sourceApplication=amap&lat="+geoAddress.getLatitude()+"&lon="+geoAddress.getLongitude()+"&dev=1&style=2"))
.withFlags(Intent.FLAG_NOT_OHOS_COMPONENT)
.build();
intent1.setOperation(operation);
startAbility(intent1);
}catch (Exception e){
e.printStackTrace();
}
} private void requestPermission() {
if (verifySelfPermission("ohos.permission.LOCATION") != IBundleManager.PERMISSION_GRANTED) {
// 应用未被授予权限
if (canRequestPermission("ohos.permission.LOCATION")) {
// 是否可以申请弹框授权(首次申请或者用户未选择禁止且不再提示)
requestPermissionsFromUser(new String[]{"ohos.permission.LOCATION"}, MY_PERMISSIONS_REQUEST_LOCATION);
} else {
// 显示应用需要权限的理由,提示用户进入设置授权
new ToastDialog(getContext()).setText("请进入系统设置进行授权").show();
}
} else {
// 权限已被授予
requestLocation();
}
} public void requestLocation() {
locator = new Locator(this);
requestParam = new RequestParam(RequestParam.SCENE_NAVIGATION);
locatorCallback = new MyLocatorCallback();
locator.requestOnce(requestParam, locatorCallback); // 请求一次
// locator.startLocating(requestParam, locatorCallback); // 多次请求 直接启动服务
} public class MyLocatorCallback implements LocatorCallback {
@Override
public void onLocationReport(Location location) {
if (location != null) {
getUITaskDispatcher().asyncDispatch(() -> {
// (逆)地理编码转换
GeoConvert geoConvert = new GeoConvert();
try {
List<GeoAddress> list = geoConvert.getAddressFromLocation(location.getLatitude(), location.getLongitude(), 1);
GeoAddress geoAddress = list.get(0);
if (geoAddress == null)
return;
new ToastDialog(getContext())
.setText("当前位置:经度:" + location.getLongitude() + "\n纬度:" + location.getLatitude()
+ "\n国家:" + geoAddress.getCountryName())
.show();
// "位置:" + geoAddress.getPlaceName()
} catch (IOException e) {
e.printStackTrace();
}
});
}
} @Override
public void onStatusChanged(int type) {
} @Override
public void onErrorReport(int type) {
}
} // 初始化WebView
private void initWebView() {
webView = (WebView) findComponentById(ResourceTable.Id_webview);
webView.getWebConfig().setJavaScriptPermit(true); // 如果网页需要使用JavaScript,增加此行
webView.getWebConfig().setWebStoragePermit(true);
webView.setWebAgent(new WebAgent() {
@Override
public ResourceResponse processResourceRequest(WebView webview, ResourceRequest request) {
final String authority = "com.jarchie.h5";
final String rawFile = "/rawfile/";
final String local = "/local/";
Uri requestUri = request.getRequestUrl();
if (authority.equals(requestUri.getDecodedAuthority())) {
String path = requestUri.getDecodedPath();
if (TextTool.isNullOrEmpty(path)) {
return super.processResourceRequest(webview, request);
}
if (path.startsWith(rawFile)) {
// 根据自定义规则访问资源文件
String rawFilePath = "entry/resources/rawfile/" + path.replace(rawFile, "");
String mimeType = URLConnection.guessContentTypeFromName(rawFilePath);
try {
Resource resource = getResourceManager().getRawFileEntry(rawFilePath).openRawFile();
ResourceResponse response = new ResourceResponse(mimeType, resource, null);
return response;
} catch (IOException e) {
HiLog.info(TAG, "open raw file failed");
}
}
if (path.startsWith(local)) {
// 根据自定义规则访问本地文件
String localFile = getContext().getFilesDir() + path.replace(local, "/");
HiLog.info(TAG, "open local file " + localFile);
File file = new File(localFile);
if (!file.exists()) {
HiLog.info(TAG, "file not exists");
return super.processResourceRequest(webview, request);
}
String mimeType = URLConnection.guessContentTypeFromName(localFile);
try {
InputStream inputStream = new FileInputStream(file);
ResourceResponse response = new ResourceResponse(mimeType, inputStream, null);
return response;
} catch (IOException e) {
HiLog.info(TAG, "open local file failed");
}
}
}
return super.processResourceRequest(webview, request);
}
});
webView.load("https://com.jarchie.h5/rawfile/test.html");
} // 初始化返回文本
private void initBackText() {
backText = (Text) findComponentById(ResourceTable.Id_back);
backText.setClickedListener(component -> onBackPressed());
} @Override
public void onActive() {
HiLog.info(TAG, "onActive:");
super.onActive();
} @Override
public void onForeground(Intent intent) {
HiLog.info(TAG, "onForeground:");
super.onForeground(intent);
} @Override
protected void onStop() {
HiLog.info(TAG, "onStop:");
super.onStop();
locator.stopLocating(locatorCallback);
}
}

【HarmonyOS】一文教你如何在H5页面中使用电话、定位及导航的更多相关文章

  1. H5页面中唤起native app

    现在各类app,分享出去的H5页面中,一般都会带着一个立即打开的按钮,如果本地安装了app,那么就直接唤起本地的app,如果没有安装,则跳转到下载.这是一个很正常的推广和导流量的策略,最近产品经理就提 ...

  2. 如何在PHP页面中原样输出HTML代码(是该找本php的数来看了)

    如何在PHP页面中原样输出HTML代码(是该找本php的数来看了) 一.总结 一句话总结:字符串与HTML之间的相互转换主要应用htmlentities()函数来完成. 1.php中的html标签如何 ...

  3. H5页面中判断是安卓手机还是ios手机的方法;APP页面中嵌套的H5跳转到APP其他页面的方法。

    (一).在H5页面中,可以直接利用如下的方法来进行判断是安卓还是ios. var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linu ...

  4. 前端视频直播技术总结及video.js在h5页面中的应用

    全手打原创,转载请标明出处:https://www.cnblogs.com/dreamsqin/p/12557070.html,多谢,=.=~ (如果对你有帮助的话请帮我点个赞啦) 目前有一个需求是在 ...

  5. 前端如何在h5页面调用微信支付?

    在微信服务号开发的时候经常会遇到微信支付的功能实现,通过实际经验自己总结了一下,前端在H5页面调起微信支付有两种办法,一是利用内置对象,二是通过引用微信的js sdk,亲测都能支付成功,从写法上来看用 ...

  6. H5页面中尝试调起APP

    安卓版本5.0以上 IOS版本10.0以上 采用事件触发的方式处理唤醒APP 市面上常见的功能 这种功能现如今应该非常普遍了,淘宝H5,知乎H5等等... 点击后会调起APP或者打开下载页面或者直接进 ...

  7. vue项目引入FastClick组件解决IOS系统下h5页面中的按钮点击延迟,连续点击无反应的问题

    异常描述: ios系统手机中访问h5页面,按钮点击有延迟,连续点击卡顿.无反应. 异常原因: 这要追溯至 2007 年初.苹果公司在发布首款 iPhone 前夕,遇到一个问题:当时的网站都是为大屏幕设 ...

  8. 前端:微信支付和支付宝支付在pc端和h5页面中的应用

    1:h5微信支付 使用的是https://pay.weixin.qq.com/wiki/doc/api/index.html  中的 (1):公司需要首先要配置公众号微信支付地址和测试白名单(支付的时 ...

  9. 小程序:如何在wxml页面中调用JavaScript函数

    早上过来遇到一个这样的bug: 在计算百分比的时候没有保留小数点后2位,从而导致一些无法整除的结果显示太长 一开始,我以为这是一个很普通的bug,既然wxml在页面{{}}内支持简单的运算,我想也应该 ...

  10. 如何在aspx页面中使用ascx控件(用户自定义的一个控件)?

    aspx是页面文件ascx是用户控件,用户控件必须嵌入到aspx中才能使用. ascx是用户控件,相当于模板 其实ascx你可以理解为Html里的一部分代码,只是嵌到aspx里而已,因为aspx内容多 ...

随机推荐

  1. MySQL explain 和 profiling 详解

    MySQL explain 和 profiling 详解 mysql explain MySQL 的 EXPLAIN 是一个用于查询优化的工具,它可以显示 MySQL 数据库如何执行查询.它返回一组关 ...

  2. [Windows]解决:windows连接远程桌面-出现身份验证错误,要求的函数不受支持( CredSSP加密数据库修正)[转载]

    文由 需要在本地Windows系统电脑通过远程桌面(mstsc)另一台Windows服务器,将其内的数据拷贝过来.但却发生了这样的异常 解决方案 step1 Win+R step2 打开注册表: gp ...

  3. 五月十三号Java基础知识点

    1.getFields()和getMethods()方法获得权限为public的本类的以及父类继承的成员变量和成员方法2.getDeclaredFields()和getDeclaredMethods( ...

  4. DG修复:清理归档配置归档清理脚本

    问题描述:DG同步断了十天,发现FRA归档盘符满了.需要清理下,重新增量恢复DG Error 12528 received logging on to the standby FAL[client, ...

  5. CI框架内置分页代码

    Controller 控制器代码 <?php defined('BASEPATH') OR exit('No direct script access allowed'); class Welc ...

  6. .NET敏捷开发框架-RDIFramework.NET V5.1发布(跨平台)

    RDIFramework.NET,基于全新.NET Framework与.NET Core的快速信息化系统敏捷开发.整合框架,给用户和开发者最佳的.Net框架部署方案.为企业快速构建跨平台.企业级的应 ...

  7. GPT-4:思考的曙光还是数据的缩影?

    海盗分金,GPT-4初露锋芒 GPT系列模型横空出世后,其是否真实具有思考和推理的能力一直被业界关注.GPT-3.5在多条狗问题和海盗分金问题上表现糟糕.GPT-4在这两个谜题上给出的答案令人惊喜,甚 ...

  8. PyTorch基础(Numpy & Tensor)

    Numpy与Tensor是PyTorch的重要内容 Numpy的使用 Numpy是Python中科学计算的一个基础包,提供了一个多维度的数组对象,数组是由numpy.ndarray类来实现的,是Num ...

  9. switch case 穿透 示例

    public class SwitchCase { //判断输入的月份属于第几季度 public static void main(String[] args) { //随机获得 1-12个月份中的一 ...

  10. JAVA注解@Scheduled 不执行

    spring boot项目需要在启动类加上注解 @EnableScheduling 定义一个接口 StockTask.java 1 public interface StockTask { 2 pub ...