让你的iOS应用程序支持运行JavaScript脚本:JavaScriptCore框架详解(四)

简介: 让你的iOS应用程序支持运行JavaScript脚本:JavaScriptCore框架详解

八、Hybird App 构建思路


   Hybird App是指混合模式移动应用,即其中既包含原生的结构有内嵌有Web的组件。这种App不仅性能和用户体验可以达到和原生所差无几的程度,更大的优势在于bug修复快,版本迭代无需发版。3月8日苹果给许多开发者发送了一封警告邮件,主要是提示开发者下载脚本动态更改App原本行为的做法将会被提审拒绝。其实这次邮件所提内容和Hybird App并无太大关系(对ReactNative也没有影响),苹果警告的是网络下发脚本并且使用runtime动态修改Native行为的应用,Hybird App的实质并没有修改原Native的行为,而是将下发的资源进行加载和界面渲染,类似WebView。


   关于混合开发,我们有两种模式:


   1.Native内嵌WebView,通过JS与OC交互实现业务无缝的衔接。


   无论是UIWebView还是WKWebKit,我们都可以在其中拿到当前的JSContext,然是使用前面介绍的方法便可以实现数据互通与交互。这种方式是最简单的混合开发,但其性能和原生相比要差一些。示意图如下:


image.png


   2.下发JS脚本,使用类似ReactNative的框架进行原生渲染


   这是一种效率非常高的混合开发模式,并且ReactNative也本身支持android和iOS公用一套代码。我们也可以使用JavaScriptCore自己实现一套解析逻辑,使用JavaScript来编写Native应用,要完整实现这样一套东西太复杂了,我们也没有能力完成一个如此庞大的工程,但是我们可以做一个小Demo来模拟其原理,这样可以更好的帮助我们理解Hybird App的构建原理。


我们打算实现这样的功能:通过下发JS脚本创建原生的UILabel标签与UIButton控件,首先编写JS代码如下:


(function(){

   console.log("ProgectInit");

   //JS脚本加载完成后 自动render界面

   return render();

})();


//JS标签类

function Label(rect,text,color){

   this.rect = rect;

   this.text = text;

   this.color = color;

   this.typeName = "Label";

}

//JS按钮类

function Button(rect,text,callFunc){

   this.rect = rect;

   this.text = text;

   this.callFunc = callFunc;

   this.typeName = "Button";

}

//JS Rect类

function Rect(x,y,width,height){

   this.x = x;

   this.y = y;

   this.width = width;

   this.height = height;

}

//JS颜色类

function Color(r,g,b,a){

   this.r = r;

   this.g = g;

   this.b = b;

   this.a = a;

}

//渲染方法 界面的渲染写在这里面

function render(){

   var rect = new Rect(20,100,280,30);

   var color = new Color(1,0,0,1);

   var label = new Label(rect,"Hello World",color);

   var rect2 = new Rect(20,150,280,30);

   var color2 = new Color(0,1,0,1);

   var label2 = new Label(rect2,"Hello Native",color2);

   var rect3 = new Rect(20,200,280,30);

   var color3 = new Color(0,0,1,1);

   var label3 = new Label(rect3,"Hello JavaScript",color3);

   var rect4 = new Rect(20,240,280,30);

   var button = new Button(rect4,"我是一个按钮",function(){

                           var randColor = new Color(Math.random(),Math.random(),Math.random(),1);

                           Globle.changeBackgroundColor(randColor);

                           });

   //将控件以数组形式返回

   return [label,label2,label3,button];

}


创建一个Objective-C类绑定到JS全局对象上,作为OC方法的桥接器:


//.h

#import <Foundation/Foundation.h>

#import <UIKit/UIKit.h>

#import <JavaScriptCore/JavaScriptCore.h>

@protocol GloblePrptocol <JSExport>

-(void)changeBackgroundColor:(JSValue *)value;

@end

@interface Globle : NSObject<GloblePrptocol>

@property(nonatomic,weak)UIViewController * ownerController;

@end

//.m

#import "Globle.h"


@implementation Globle

-(void)changeBackgroundColor:(JSValue *)value{

   self.ownerController.view.backgroundColor = [UIColor colorWithRed:value[@"r"].toDouble green:value[@"g"].toDouble blue:value[@"b"].toDouble alpha:value[@"a"].toDouble];

}

@end

在ViewController中实现一个界面渲染的render解释方法,并建立按钮的方法转换,如下:


//

//  ViewController.m

//  JavaScriptCoreTest

//

//  Created by vip on 17/3/6.

//  Copyright © 2017年 jaki. All rights reserved.

//


#import "ViewController.h"

#import <JavaScriptCore/JavaScriptCore.h>

#import "Globle.h"

@interface ViewController ()


@property(nonatomic,strong)JSContext * jsContext;

@property(nonatomic,strong)NSMutableArray * actionArray;

@property(nonatomic,strong)Globle * globle;

@end


@implementation ViewController


- (void)viewDidLoad {

   [super viewDidLoad];

   //创建JS运行环境

   self.jsContext = [JSContext new];

   //绑定桥接器

   self.globle =  [Globle new];

   self.globle.ownerController = self;

   self.jsContext[@"Globle"] = self.globle;

   self.actionArray = [NSMutableArray array];

   [self render];

}

//界面渲染解释器

-(void)render{

   NSString * path = [[NSBundle mainBundle] pathForResource:@"main" ofType:@"js"];

   NSData * jsData = [[NSData alloc]initWithContentsOfFile:path];

   NSString * jsCode = [[NSString alloc]initWithData:jsData encoding:NSUTF8StringEncoding];

   JSValue * jsVlaue = [self.jsContext evaluateScript:jsCode];

   for (int i=0; i<jsVlaue.toArray.count; i++) {

       JSValue * subValue = [jsVlaue objectAtIndexedSubscript:i];

       if ([[subValue objectForKeyedSubscript:@"typeName"].toString isEqualToString:@"Label"]) {

           UILabel * label = [UILabel new];

           label.frame = CGRectMake(subValue[@"rect"][@"x"].toDouble, subValue[@"rect"][@"y"].toDouble, subValue[@"rect"][@"width"].toDouble, subValue[@"rect"][@"height"].toDouble);

           label.text = subValue[@"text"].toString;

           label.textColor = [UIColor colorWithRed:subValue[@"color"][@"r"].toDouble green:subValue[@"color"][@"g"].toDouble blue:subValue[@"color"][@"b"].toDouble alpha:subValue[@"color"][@"a"].toDouble];

           [self.view addSubview:label];

       }else if ([[subValue objectForKeyedSubscript:@"typeName"].toString isEqualToString:@"Button"]){

           UIButton * button = [UIButton buttonWithType:UIButtonTypeSystem];

           button.frame = CGRectMake(subValue[@"rect"][@"x"].toDouble, subValue[@"rect"][@"y"].toDouble, subValue[@"rect"][@"width"].toDouble, subValue[@"rect"][@"height"].toDouble);

           [button setTitle:subValue[@"text"].toString forState:UIControlStateNormal];

           button.tag = self.actionArray.count;

           [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];

           [self.actionArray addObject:subValue[@"callFunc"]];

           [self.view addSubview:button];

         

       }

   }

}

//按钮转换方法

-(void)buttonAction:(UIButton *)btn{

   JSValue * action  = self.actionArray[btn.tag];

   //执行JS方法

   [action callWithArguments:nil];

}




@end

运行工程,效果如下图所示,点击按钮即可实现简单的界面颜色切换:

image.png



上面的示例工程我只实现了UILabel类与UIButton类的JS-OC转换,如果将原生控件和JS对象再进行一层绑定,并且实现大部分JS类与原生类和他们内部的属性,则我们就开发了一套Hybird App开发框架,但并没有这个必要,如果你对更多兴趣,可以深入学习下ReactNative。


   文中的示例Demo我放在了Github上,地址如下:https://github.com/ZYHshao/Demo-Hybird

目录
相关文章
|
2月前
|
数据采集 人工智能 自然语言处理
Midscene.js:AI 驱动的 UI 自动化测试框架,支持自然语言交互,生成可视化报告
Midscene.js 是一款基于 AI 技术的 UI 自动化测试框架,通过自然语言交互简化测试流程,支持动作执行、数据查询和页面断言,提供可视化报告,适用于多种应用场景。
548 1
Midscene.js:AI 驱动的 UI 自动化测试框架,支持自然语言交互,生成可视化报告
|
3月前
|
缓存 监控 JavaScript
Vue.js 框架下的性能优化策略与实践
Vue.js 框架下的性能优化策略与实践
|
3月前
|
开发框架 JavaScript 前端开发
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势。通过明确的类型定义,TypeScript 能够在编码阶段发现潜在错误,提高代码质量;支持组件的清晰定义与复用,增强代码的可维护性;与 React、Vue 等框架结合,提供更佳的开发体验;适用于大型项目,优化代码结构和性能。随着 Web 技术的发展,TypeScript 的应用前景广阔,将继续引领 Web 开发的新趋势。
66 2
|
3月前
|
缓存 负载均衡 JavaScript
构建高效后端服务:Node.js与Express框架实践
在数字化时代的浪潮中,后端服务的重要性不言而喻。本文将通过深入浅出的方式介绍如何利用Node.js及其强大的Express框架来搭建一个高效的后端服务。我们将从零开始,逐步深入,不仅涉及基础的代码编写,更会探讨如何优化性能和处理高并发场景。无论你是后端新手还是希望提高现有技能的开发者,这篇文章都将为你提供宝贵的知识和启示。
|
3月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
353 4
|
3月前
|
安全 Swift iOS开发
Swift 与 UIKit 在 iOS 应用界面开发中的关键技术和实践方法
本文深入探讨了 Swift 与 UIKit 在 iOS 应用界面开发中的关键技术和实践方法。Swift 以其简洁、高效和类型安全的特点,结合 UIKit 丰富的组件和功能,为开发者提供了强大的工具。文章从 Swift 的语法优势、类型安全、编程模型以及与 UIKit 的集成,到 UIKit 的主要组件和功能,再到构建界面的实践技巧和实际案例分析,全面介绍了如何利用这些技术创建高质量的用户界面。
72 2
|
3月前
|
JavaScript 前端开发 开发者
JavaScript框架React vs. Vue:一场性能与易用性的较量
JavaScript框架React vs. Vue:一场性能与易用性的较量
67 0
|
3月前
|
JSON 前端开发 API
探索iOS开发之旅:打造你的第一个天气应用
【10月更文挑战第36天】在这篇文章中,我们将踏上一段激动人心的旅程,一起构建属于我们自己的iOS天气应用。通过这个实战项目,你将学习到如何从零开始搭建一个iOS应用,掌握基本的用户界面设计、网络请求处理以及数据解析等核心技能。无论你是编程新手还是希望扩展你的iOS开发技能,这个项目都将为你提供宝贵的实践经验。准备好了吗?让我们开始吧!
|
3月前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js后端框架
【10月更文挑战第34天】在数字化时代,后端开发如同一座桥梁,连接着用户界面与数据处理的两端。本文将通过Node.js这一轻量级、高效的平台,带领读者领略后端框架的魅力。我们将从基础概念出发,逐步深入到实战应用,最后探讨如何通过代码示例来巩固学习成果,使读者能够在理论与实践之间架起自己的桥梁。
|
3月前
|
Web App开发 JavaScript 前端开发
构建高效后端服务:Node.js与Express框架的实践
【10月更文挑战第33天】在数字化时代的浪潮中,后端服务的效率和可靠性成为企业竞争的关键。本文将深入探讨如何利用Node.js和Express框架构建高效且易于维护的后端服务。通过实践案例和代码示例,我们将揭示这一组合如何简化开发流程、优化性能,并提升用户体验。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的见解和实用技巧。

热门文章

最新文章

  • 1
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    14
  • 2
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    28
  • 3
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    34
  • 4
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    29
  • 5
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    23
  • 6
    uniapp开发ios打包Error code = -5000 Error message: Error: certificate file(p12) import failed!报错问题如何解决
    143
  • 7
    【05】2025年1月首发完整版-篇幅较长-苹果app如何上架到app store完整流程·不借助第三方上架工具的情况下无需花钱但需仔细学习-优雅草央千澈详解关于APP签名以及分发-们最关心的一篇来了-IOS上架app
    235
  • 8
    app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
    90
  • 9
    深入探索iOS开发中的SwiftUI框架
    145
  • 10
    ios样式开关按钮jQuery插件
    60