开发Hybrid App的技术选型

简介: 开发Hybrid App的技术选型

一、前言

如果我们把Hybrid App理解为运行在android或者ios以及其他移动终端设备上的应用,也可以叫做H5 APP,这种开发应用的模式结合web开发技术与Native开发的部分技术,通常也被称为混合开发模式。

二、移动应用开发的三种方式

  • Native App:原生应用,在android端通常使用Java或Kotlin开发,ios端使用OC或者Swift开发
  • Hybrid App:混合应用,结合Web与Native技术开发
  • Web App:web应用,网页三剑客html+css+js

Native App开发依旧是移动应用的主导,但如今的Native App或多或少会嵌入一些web页面,诸如淘宝、京东等APP,所以如今真正意义上的原生应用又该如何去定义呢?Hybrid App受到越来越多开发者的追捧与其开发周期短,开发难度小,跨平台离不开,当然APP的效果也成为大家诟病的话题,如首屏打开缓慢,动画效果不够流畅等。

三种方式的技术比较(图片来自网络)

三、Hybrid App开发的核心

毫无疑问,webview是Hybrid App开发的核心。webview可以简单的理解为一个浏览器。webview 使用的是手机自带的浏览器内核,一般来说,手机厂家在内置浏览器的时候都会对其内核做一定的修改,所以在webview渲染的内容可能或有些差异,但是这基本上不影响APP的开发。绝大部分手机都使用的是WebKit作为webview的渲染引擎。关于WebKit以及其他的浏览器内核知识可以查看这里

关于webview的知识点非常多,如在android上常用的属性:WebSettings、WebViewClient,与JavaScript的交互,js注入漏洞,jsBridge等等,在此以Kotlin为例实现一个简单的例子,项目源码点击这里

MAinActivity.kt

package com.example.wxqdoit.kotlintest
import android.os.Build
import android.os.Bundle
import android.support.annotation.RequiresApi
import android.support.design.widget.BottomNavigationView
import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
    @RequiresApi(Build.VERSION_CODES.O)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        bottom_navigation.setOnNavigationItemSelectedListener(mBottomNavigationView)
        val fragments: MutableList<Fragment> = ArrayList<Fragment>()
        fragments.add(Fragment1("https://www.baidu.com"))
        fragments.add(Fragment1("https://www.jianshu.com"))
        fragments.add(Fragment1("https://aidn.jp/mikutap/"))
        vp_main.adapter = ViewPagerAdapter(supportFragmentManager,fragments)
    }
    private val mBottomNavigationView = BottomNavigationView.OnNavigationItemSelectedListener { item ->
        when (item.itemId) {
            R.id.word -> {
                //vp_main.currentItem = 0
                Toast.makeText(this,"点击了",Toast.LENGTH_SHORT).show()
                return@OnNavigationItemSelectedListener true
            }
            R.id.pic -> {
                //vp_main.currentItem = 1
                return@OnNavigationItemSelectedListener true
            }
            R.id.me -> {
                //vp_main.currentItem = 2
                return@OnNavigationItemSelectedListener true
            }
        }
        false
    }
}

ViewPagerAdapter.kt

package com.example.wxqdoit.kotlintest
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v4.app.FragmentPagerAdapter
//继承 FragmentPagerAdapter 创建适配器
class ViewPagerAdapter(fm: FragmentManager?, var list: List<Fragment>) : FragmentPagerAdapter(fm) {
    override fun getItem(position: Int): Fragment {
        return list.get(position)
    }
    override fun getCount(): Int {
        return list.size
    }
}

Fragment1.kt

package com.example.wxqdoit.kotlintest
import android.annotation.SuppressLint
import android.os.Build
import android.os.Bundle
import android.support.annotation.RequiresApi
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
import kotlinx.android.synthetic.main.fragment1.view.*
@SuppressLint("ValidFragment")
class Fragment1(private val url: String):Fragment() {
    @SuppressLint("SetJavaScriptEnabled")
    @RequiresApi(Build.VERSION_CODES.O)
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment1, container, false)
        val webView = view.testWebView
        webView!!.webViewClient = webClient
        webView.settings.javaScriptEnabled = true
        webView.settings.allowContentAccess = true
        webView.settings.layoutAlgorithm
        webView.loadUrl(url)
        return view
    }
    private val webClient = object : WebViewClient() {
        @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
        override fun shouldOverrideUrlLoading(view: WebView, request:WebResourceRequest ): Boolean {
            view.loadUrl(request.url.toString())
            return true
        }
    }
}

效果如下

四、移动APP适配

做过原生开发的都知道美术需要出几套图以适配不同的分辨率,720×1280、750×1334、1080×1920、1242×2208,更大或者更小的屏在市面上也常见,android上字体大小通常以dp、sp作为单位。Hybrid App在只有一套美术UI的情况下应当如何处理以适配不同的机型呢?

媒体查询、百分比,或是直接使用web端常用的单位px、em、rem以及vh、vw,都是常用的适配方案。在设计稿给到固定宽度的情况下,相对而言,使用rem作为单位是比较合理的选择,至于移动设备适配,屏幕宽度,逻辑像素、物理像素、dpi等知识就不在此处赘述,分享优秀的博客:

移动设备适配基础知识速成:weibo.com/p/1001603933391216084991

五、flexible.js

flexible是淘宝使用的移动端适配方案,原理即根据机型分辨率进行适配,设置根font-size,使用相对单位rem。其核心功能如下:

  • 判断meta标签,动态改写标签
  • 给html标签添加data-dpr属性
  • 给html标签添加font-size属性

根font-size(即html标签上的)属性值即为一个单位的rem,在chrome浏览器上,默认的font-size值为16px:即16px=1rem

getComputedStyle(document.getElementsByTagName("html")[0])["font-size"];
//16px

flexible.js核心代码:

function refreshRem(){
        var width = docEl.getBoundingClientRect().width;
        if (width / dpr > 540) {
            width = 540 * dpr;
        }
        var rem = width / 10;
        docEl.style.fontSize = rem + 'px';
        docEl.setAttribute("font-size",rem + 'px');
        flexible.rem = win.rem = rem;
    }
    win.addEventListener('resize', function() {
        clearTimeout(tid);
        tid = setTimeout(refreshRem, 200);
    }, false);
    win.addEventListener('pageshow', function(e) {
        if (e.persisted) {
            clearTimeout(tid);
            tid = setTimeout(refreshRem, 200);
        }
    }, false);

将设备宽度分为10份,而每一份视作一个单位,再将html的font-size设置为这个单位即:

font-size = 750/10 = 75px;

1rem = 75px;

如果在宽度为750px的设备上,完全符合上述换算。如果在iphone6/7/8上,宽度为375,那么:

font-size = 375/10 = 37.5px;

1rem = 37.5px;

现在以宽为750的设计稿为例,有一个款750px高75px的按钮 ;在iphone6/7/8上(实际宽375px)我们实际看到的宽高是多少呢?

width = 750/75 = 10rem ---> 10rem(在iphone6/7/8上) = 37.5px*10 = 375px;

height = 75/75 = 1rem --->1rem(在iphone6/7/8上) = 37.5px;

不难看出,只需要将这个单位作为除数即可计算出所需要的值;

六、打包工具

开发完成之后使用hbuilder或cordova打包成为android APK或者ios IPA。我更偏向于cordova,插件相对更多,社区更加活跃,稳定的更新维护。当然,孰优孰劣各自体会。下文会具体介绍cordova的相关知识。

Hbuild:http://www.dcloud.io/

cordova:https://cordova.apache.org/

七、UI框架

开发框架常用的有ionic,mui,jQuery Mobile,weui等等。就事实而论,当设计稿给到开发者时,或者这些都用不到,全套UI自己写也是常见的。

八、angular、react还是vue?

angular、react相对而言比较重,vue显得轻量一些,当开发大型SPA应用时,前两者是不错的选择,而vue完整的工具链以及活跃的社区也适应绝大部分的开发场景。

九、jQuery还用吗?

对于事件的封装,DOM操作的实现都是毫无疑问需要使用的,同时集成的ajax封装也必不可少,不过不论是Web APP的开发还是 Hybrid App的开发,jq都是不二之选。但当我们在对请求过滤的处理时,这些get,post方法基本上不能满足我们的需求,所以需要对请求进行二次封装。

/**
     * 通用请求数据接口
     * @param reqUrl
     * @param reqType
     * @param data
     * @param fn
     */
    commonRequest: function commonRequest(reqUrl, reqType, data, fn) {
        $.ajax({
            url: reqUrl,
            type: reqType,
            data: data,
            async: false,
            success: function success(data) {
                fn(data);
            },
            error: function error(data) {
                $.lightTip.error("网络请求错误-" + data.status, 2000);
            }
        });
    },
    /**
     * 二次封装get请求
     * @param reqUrl
     * @param data
     * @param fn
     */
    get: function get(reqUrl, data, fn) {
        $.ajax({
            url: reqUrl,
            type: 'GET',
            data: data,
            async: false,
            success: function success(data) {
                if (data.meta.code === 200) {
                    fn(data);
                } else {
                    alert(data.meta.message);
                    throw new Error(data.meta.message);
                }
            },
            error: function error(data) {
                $.lightTip.error("网络请求错误-" + data.status, 2000);
            }
        });
    },
    /**
     * 二次封装post请求
     * @param reqUrl
     * @param data
     * @param fn
     */
    post: function post(reqUrl, data, fn) {
        $.ajax({
            url: reqUrl,
            type: 'POST',
            data: data,
            async: false,
            success: function success(data) {
                if (data.meta.code === 200) {
                    fn(data);
                } else {
                    alert(data.meta.message);
                    throw new Error(data.meta.message);
                }
            },
            error: function error(data) {
                $.lightTip.error("网络请求错误-" + data.status, 2000);
            }
        });
    },
    /**
     * formData上传数据
     * @param reqUrl
     * @param reqType
     * @param data
     * @param fn
     */
    formDataReq: function formDataReq(reqUrl, reqType, data, fn) {
        $.ajax({
            url: reqUrl,
            data: data,
            type: reqType,
            processData: false,
            contentType: false,
            success: function success(data) {
                if (data.meta.code === 200) {
                    fn(data);
                } else {
                    alert(data.meta.message);
                    throw new Error(data.meta.message);
                }
            },
            error: function error(data) {
                $.lightTip.error("网络请求错误-" + data.status, 2000);
            }
        });
    },

这样封装一次,当用户没有登录时,可以根据返回的数据进行过滤处理。

当然如果你不用jq也可以选择其他的类库如封装ajax请求的axios

十、swiper是个好东西

swiper常用于移动端网站的内容触摸滑动,是纯javascript打造的滑动特效插件,面向手机、平板电脑等移动终端,Swiper能实现触屏焦点图、触屏Tab切换、触屏多图切换等常用效。这个插件功能确实强大,官网惊艳,api文档走心,性能不错。用作APP开发的主容器亦有一战之力。

十一、cordova开发详解


1、cordova开发环境搭建,以android为例

  1、安装jdk(建议jdk8+),配置环境变量;

  2、安装android sdk(至少到27,也可以安装android studio依赖安装),配置环境变量;

  3、安装node(npm,也可以选择使用yarn)(node建议8+),如果不是默认安装,请配置环境变量;

  4、安装bower,用以下载各种前端类库;

  5、使用npm install -g cordova全局安装cordova,如果安装过慢或失败请科学上网;


2、创建一个app并运行起来

   1、cordova create [文件夹名] [包名] [app名]

$ cordova create hello com.example.hello HelloWorld

   2、添加平台(以android为例)

$ cd hello
$ cordova platform add android

   3、build项目

cordova build android
......
.....
...
.
BUILD SUCCESSFUL in 7s
47 actionable tasks: 1 executed, 46 up-to-date
Built the following apk(s):
        D:\dev\****\****\****\platforms\android\app\build\outputs\apk\debug\app-debug.apk

在路径:\platforms\android\app\build\outputs\apk\debug\app-debug.apk下可以找到apk文件。


3、常用命令

Global Commands
    create ............................. 创建项目
    help ............................... 获取帮助
    telemetry .......................... 开启或关闭遥测采集
    config ............................. 全局配置
Project Commands
    info ............................... 项目基本信息
    requirements ....................... 检查并打印出指定平台的所有要求
    platform ........................... 管理项目平台
    plugin ............................. 管理插件
    compile ............................ 编译项目
    clean .............................. 清除项目

更多命令可以到官网查看。


4、项目结构

如果项目成功运行,您看到的项目结构应该如下:

www文件夹作为开发主文件夹;

res文件夹存放app的闪屏图片和icon;

plugins文件夹存放插件;

plaatforms文件夹存放诸如android、ios等各端的文件;

node-modules文件夹自然是依赖的各个模块

config.xml是项目的配置文件,你添加的插件将会在里面显示,如状态栏插件,你可以添加更多插件。

<plugin name="cordova-plugin-statusbar" spec="^2.4.2" />


5、常用插件收集:

phonegap-plugin-barcodescanner : 二维码扫描

cordova-plugin-statusbar:状态栏

cordova-plugin-inappbrowser: 内置浏览

cordova-plugin-camera:照相机

插件太多可查看这里

官方的插件搜索地址点击这里


6、插件使用,以imagePicker为例子

cordova plugin add cordova-plugin-imagepicker

使用:

document.addEventListener("deviceready",onDeviceReady);
        function onDeviceReady(){
            console.log("onDeviceReady");
            $(document).on("tap","#getPictures",()=>{
                window.imagePicker.getPictures(
                    function(results) {
                        for (let i = 0; i < results.length; i++) {
                            console.log('Image URI: ' + results[i]);
                            alert('Image URI: ' + results[i]);
                        }
                    }, function (error) {
                        console.log('Error: ' + error);
                        alert('Error: ' + error);
                    },{
                        maxImages: 9,
                        width: 500,
                        height: 500,
                        quality:60
                    }
                );
            })
        }

当然要实现QQ登录、微信登录等功能也是完全没有问题的,只需要添加对应的插件使用就可以了。


7、构建release版本以及签名

构建release版本

cordova build android --release

对 APK 签名

jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore release-key.keystore platforms/android/build/outputs/apk/android-release-unsigned.apk [秘钥]apk签名的相关知识比较复杂,可以阅读这一篇:Cordova 打包 Android release app 过程详解

目录
相关文章
|
1天前
|
前端开发 Java 开发工具
【03】完整flutter的APP打包流程-以apk设置图标-包名-签名-APP名-打包流程为例—-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈 章节内容【03】
【03】完整flutter的APP打包流程-以apk设置图标-包名-签名-APP名-打包流程为例—-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈 章节内容【03】
【03】完整flutter的APP打包流程-以apk设置图标-包名-签名-APP名-打包流程为例—-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈 章节内容【03】
|
1天前
|
Dart 前端开发 Android开发
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
2天前
|
Dart 前端开发 架构师
【01】vs-code如何配置flutter环境-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈-供大大的学习提升
【01】vs-code如何配置flutter环境-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈-供大大的学习提升
|
18天前
|
开发框架 小程序 前端开发
圈子社交app前端+后端源码,uniapp社交兴趣圈子开发,框架php圈子小程序安装搭建
本文介绍了圈子社交APP的源码获取、分析与定制,PHP实现的圈子框架设计及代码编写,以及圈子小程序的安装搭建。涵盖环境配置、数据库设计、前后端开发与接口对接等内容,确保平台的安全性、性能和功能完整性。通过详细指导,帮助开发者快速搭建稳定可靠的圈子社交平台。
140 18
|
14天前
|
JSON 供应链 搜索推荐
淘宝APP分类API接口:开发、运用与收益全解析
淘宝APP作为国内领先的购物平台,拥有丰富的商品资源和庞大的用户群体。分类API接口是实现商品分类管理、查询及个性化推荐的关键工具。通过开发和使用该接口,商家可以构建分类树、进行商品查询与搜索、提供个性化推荐,从而提高销售额、增加商品曝光、提升用户体验并降低运营成本。此外,它还能帮助拓展业务范围,满足用户的多样化需求,推动电商业务的发展和创新。
39 5
|
14天前
|
移动开发 安全 搜索推荐
圈子社交系统APP,同城本地圈子论坛开发,让身边的人沟通更加紧密
圈子社交系统APP是一款基于社交网络的移动应用,用户可创建、加入和管理兴趣圈子。主要功能包括:动态分享与交流、实时聊天、会员体系与身份认证、活动策划等。该APP注重个性化定制、社交关系深化、隐私安全及跨平台互联,提供丰富的社交体验。
|
17天前
鸿蒙语言开发 几十套鸿蒙ArkTs app毕业设计及课程作业
鸿蒙语言开发 几十套鸿蒙ArkTs app毕业设计及课程作业
26 1
|
26天前
|
JSON 缓存 前端开发
HarmonyOS NEXT 5.0鸿蒙开发一套影院APP(附带源码)
本项目基于HarmonyOS NEXT 5.0开发了一款影院应用程序,主要实现了电影和影院信息的展示功能。应用包括首页、电影列表、影院列表等模块。首页包含轮播图与正在热映及即将上映的电影切换显示;电影列表模块通过API获取电影数据并以网格形式展示,用户可以查看电影详情;影院列表则允许用户选择城市后查看对应影院信息,并支持城市选择弹窗。此外,项目中还集成了Axios用于网络请求,并进行了二次封装以简化接口调用流程,同时添加了请求和响应拦截器来处理通用逻辑。整体代码结构清晰,使用了组件化开发方式,便于维护和扩展。 该简介概括了提供的内容,但请注意实际开发中还需考虑UI优化、性能提升等方面的工作。
91 11
|
23天前
|
前端开发 数据库 UED
uniapp开发,前后端分离的陪玩系统优势,陪玩app功能特点,线上聊天线下陪玩,只要4800
前后端分离的陪玩系统将前端(用户界面)和后端(服务器逻辑)分开开发,前者负责页面渲染与用户交互,后者处理数据并提供接口。该架构提高开发效率、优化用户体验、增强可扩展性和稳定性,降低维护成本,提升安全性。玩家可发布陪玩需求,陪玩人员发布服务信息,支持在线聊天、预约及线下陪玩功能,满足多样化需求。[演示链接](https://www.51duoke.cn/games/?id=7)
|
22天前
|
安全 算法 机器人
双重防护!红娘相亲app搭建开发,婚恋交友系统登录方式,密码+验证码的优势
在婚恋交友系统中,密码和验证码是两种重要的安全措施。密码用于验证用户身份,应设置为复杂组合以防止未经授权的访问;验证码则通过图形或字符识别,防止自动化攻击如暴力破解和注册机器人。两者同时开启可显著提高安全性,防止暴力破解和自动化注册,提升用户信任感。建议要求强密码、定期更新验证码样式,并在可疑登录时增加验证码复杂性。这样既能保障用户信息安全,又兼顾了用户体验。 ![交友11111.jpg](https://ucc.alicdn.com/pic/developer-ecology/hy2p6wcvgk4oe_c9eb8d6eb8144866b0cd1d96ffb0c907.jpg)

热门文章

最新文章