当前位置: > > > Swift - 使用HTML5进行iOS开发(将HTML5打包成iOS应用)

Swift - 使用HTML5进行iOS开发(将HTML5打包成iOS应用)

最近越来越流行使用HTML5进行跨平台应用开发,先不说运行效率如何。从人力成本来说,只要写一套html页面就可以打包发布到安卓和iOS等多个平台,确实会省下不少时间和人力(这个领导最喜欢了)。
下面简单介绍下如何把HTML5编写的页面编译成iOS应用,以及如何让页面与Swift代码进行交互。(本文代码已升级至Swift3)

1,使用UIWebView还是WKWebView来加载html页面
原来我们一直使用UIWebView来加载web页面。从iOS8起,苹果提供了WKWebView用来代替UIWebView。
虽然WKWebView不支持缓存和NSURLProtocol 拦截了,但其加载速度比UIWebView提升差不多一倍的, 内存使用上面反而还少了一半。同时也增加了加载进度条属性,而不像原来要使用假的进度条。原生代码与页面js互相调用也更加方便。  
所有在缓存要求不高的情况下,建议使用WKWebView,用户体验也会更好。
 
2,使用UIWebView和WKWebView加载html页面
我们可以整个应用都使用HTML5来编写,或者只有某几个页面使用HTML。
先把HTML5的页面导入到项目中来,然后再使用UIWebView或WKWebView加载显示。(除了导入到本地工程里,把html页面放在服务器上远程加载也是可以的)


(注意:添加文件的时候有两种方式:“Create groups”和“Create folder references”。如果你的html页面有层次结构,比如css,js,图片都放在各自的子文件夹中。要选择后面那个方式“Create folder references”。如果选第一个,虽然在Xcode组织树看来都是好的,但实际所有加入到项目的文件都会在mainBundle根路径下,这样文件引用就会出问题。)


(1)下面是使用UIWebView的样例:
import UIKit
import WebKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let path = Bundle.main.path(forResource: "index", ofType: ".html",
                                                         inDirectory: "HTML5")
        let url = URL(fileURLWithPath:path!)
        let request = URLRequest(url:url)
        
        //将浏览器视图全屏(在内容区域全屏,不占用顶端时间条)
        let frame = CGRect(x:0, y:20, width:UIScreen.main.bounds.width,
                           height:UIScreen.main.bounds.height)
        let theWebView = UIWebView(frame:frame)
        //禁用页面在最顶端时下拉拖动效果
        theWebView.scrollView.bounces = false
        //加载页面
        theWebView.loadRequest(request)
        self.view.addSubview(theWebView)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

(2)下面是使用WKWebView的样例:
import UIKit
import WebKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let path = Bundle.main.path(forResource: "index", ofType: ".html",
                                    inDirectory: "HTML5")
        let url = URL(fileURLWithPath:path!)
        let request = URLRequest(url:url)
        
        //将浏览器视图全屏(在内容区域全屏,不占用顶端时间条)
        let frame = CGRect(x:0, y:20, width:UIScreen.main.bounds.width,
                           height:UIScreen.main.bounds.height)
        let theWebView:WKWebView = WKWebView(frame:frame)
        //禁用页面在最顶端时下拉拖动效果
        theWebView.scrollView.bounces = false
        //加载页面
        theWebView.load(request)
        self.view.addSubview(theWebView)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

3,swift代码与页面js互相调用(使用WKWebView)
下面通过一个简单样例演示js与原生代码如何进行相互调用以及参数传递。当点击一个商品图片时,会弹出一个iOS的消息框。当用户选择确定后,又会调用页面js方法,把商品添加到购物车里面。


--- Swift代码 ViewController.swift ---
import UIKit
import WebKit

class ViewController: UIViewController, WKScriptMessageHandler{
    
    var theWebView:WKWebView?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let path = Bundle.main.path(forResource: "index", ofType: ".html",
                                    inDirectory: "HTML5")
        let url = URL(fileURLWithPath:path!)
        let request = URLRequest(url:url)
        
        //创建供js调用的接口
        let theConfiguration = WKWebViewConfiguration()
        theConfiguration.userContentController.add(self, name: "interOp")
        
        //将浏览器视图全屏(在内容区域全屏,不占用顶端时间条)
        let frame = CGRect(x:0, y:20, width:UIScreen.main.bounds.width,
                           height:UIScreen.main.bounds.height)
        theWebView = WKWebView(frame:frame, configuration: theConfiguration)
        //禁用页面在最顶端时下拉拖动效果
        theWebView!.scrollView.bounces = false
        //加载页面
        theWebView!.load(request)
        self.view.addSubview(theWebView!)
    }
    
    //响应处理js那边的调用
    func userContentController(_ userContentController:WKUserContentController,
                               didReceive message: WKScriptMessage) {
        print(message.body)
        let sentData = message.body as! Dictionary<String,String>
        //判断是确认添加购物车操作
        if(sentData["method"] == "addToCarCheck"){
            //获取商品名称
            let itemName = sentData["name"]!
            let alertController = UIAlertController(title: "系统提示",
                                        message: "确定把\(itemName)添加到购物车吗?",
                                        preferredStyle: .alert)
            let cancelAction = UIAlertAction(title: "取消", style: .cancel, handler: nil)
            let okAction = UIAlertAction(title: "确定", style: .default, handler: {
                action in
                print("点击了确定")
                //调用页面里加入购物车js方法
                self.theWebView!.evaluateJavaScript("addToCar('\(itemName)')",
                    completionHandler: nil)
            })
            alertController.addAction(cancelAction)
            alertController.addAction(okAction)
            self.present(alertController, animated: true, completion: nil)
        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

--- html页面 index.html(这里只展示主要js代码,还用到了jQuery) ---
<script>
$(function() {
	//点击商品添加到购物车
	$(".goodsItem").click(function() {
		var itemName = $(this).children("img")[0].alt;
		var message = {"method":"addToCarCheck","name":itemName};
		window.webkit.messageHandlers.interOp.postMessage(message);
	});
});
    

//添加到购物车
function addToCar(itemName){
    //这里只是简单的给数量+1,用来演示
    var num = parseInt($("#cartNums").text());
    $("#cartNums").text(num+1);
}	 
</script>

源码下载:
HTML5.zip(2015-09-22 Swift2)
hangge_876.zip(2016-10-15 Swift3 最新版)

评论14
  • 14楼
    2018-01-11 21:57
    小道消息

    遇到一个天坑,WKWebView无法加载沙盒中的HTML文件,但是能加载Bundle中的HTML文件,请问如何解决?

    站长回复

    沙盒里的文件是可以加载的啊,你检查下是不是路径什么写错了。

  • 13楼
    2017-11-14 04:34
    AlexLLL

    航哥我已经实现了WKWebView加载html页面,但是加载不了导航条。storyboard加了导航条也没用啊。我想实现“返回/前进”
    好像WKWebView直接盖住了导航条…… 怎么做呢

    站长回复

    如果有导航条,WKWebView就不能设置为全屏。你调整下WKWebView的起始位置(主要是y坐标),不要让它挡住导航条就好了。

  • 12楼
    2017-10-27 11:36
    lb

    航哥,比如你这个案例里面,如果你的那些图片是在swift里面获取的(也就是将他们取活的数据),通过“evaluateJavaScript”传递到HTML生成页面,该怎么获取点击的是哪一张图?我现在做的是传递一个<tr><td></td></tr>表格,但是无法获取到点击的是哪一个。请问有办法解决吗?

    站长回复

    通常做法是将数据传递进去(不是直接拼个表格传进去),然后html里面通过js根据传入的数据生成表格。 表格生成完毕后,再使用js给生成的单元格添加点击事件。

    (不过既然是H5开发,理论上还是建议直接在html页面里发请求、取数据、显示数据)

  • 11楼
    2016-10-09 08:53
    ios新手

    你好,能不能弄个swift uiWebView下拉刷新的案例,谢谢了

    站长回复

    最近刚好写了一篇相关文章:Swift - MJRefresh库的使用详解6(WebView上实现下拉刷新)

  • 10楼
    2016-07-23 14:56
    落花灯

    我加载本地h5页面后,里面的链接跳转不了是怎么回事呢?

    站长回复

    我测试了下链接跳转是没问题的,你检查下代码。链接有没有写错。

    样例:<a href="about.html">关于</a>

  • 9楼
    2016-07-15 19:31
    文清

    棒棒哒

    站长回复

    谢谢你的支持与鼓励。欢迎常来看看。

  • 8楼
    2016-04-19 09:36
    bender

    怎么传递复杂的参数呢?全部转成一条string再传吗?

    站长回复

    你可以转成json字符串传递,js那边接收到解析也方便。

  • 7楼
    2016-03-17 20:27
    0

    哦 了解了 实际上这个方法self.theWebView!.evaluateJavaScript("addToCar('\(itemName)')",里是给了h5参数的 谢谢航哥

    站长回复

    是这样的,不客气:)

  • 6楼
    2016-03-16 14:33
    giving

    谢谢分享

    站长回复

    不客气,欢迎常来看看,我会持续更新的。

  • 5楼
    2016-03-14 10:41
    0

    航哥,这个是只拿取HTML的数据,有没有办法将本地数据给到HTML那边,比如HTML有登录功能,账户密码是在swift这边,怎么把账户、密码注入html,使HTML页面加载出来就直接是已登录。UIWebView能做吗?如果能做的话,麻烦用UIWebView和WKWebView各写下。谢谢 ~~

    站长回复

    我的想法是HTML页面里先要定义一个自动登录的js方法(参数是用户名和密码),WKWebView加载页面完毕后,调用这个登录js(调用的时候传入用户名、密码)即可。
    或者这个html页面改成动态页面,请求时把用户密码跟在链接后面,比如:index.php?method=login&username=hangge&password=vdfgdgfd(密码先加密下),让服务器那边处理并返回登录后的页面。

  • 4楼
    2015-12-19 10:58
    zhanghai@topepay.com

    xcode7 index是一个登录的页面,登录后跳转,但是点击登录就没有反应了,跳转不了!ps:登录的是远程的服务器,服务器上也部署了同样的代码,直接用网页是可以登录跳转的!

    站长回复

    要跳转到远程服务器上的页面,需要在Info.plist,添加如下配置:

    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>

  • 3楼
    2015-12-19 10:54
    zhanghai@topepay.com

    xcode7 index是一个登录的页面,登录后跳转,但是点击登录就没有反应了,跳转不了!

    站长回复

    要跳转到远程服务器上的页面,需要在Info.plist,添加如下配置:

    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>

  • 2楼
    2015-12-18 14:01
    zhanghai@topepay.com

    怎么只能加载首页index.html???

    站长回复

    初始加载首页,你可以自行添加新页面,在html里做好链接跳转就好了

  • 1楼
    2015-09-25 11:44
    qiang437587687

    谢谢分享 加油 !!

    站长回复

    谢谢