Commit 7cbea0cd authored by luyueming's avatar luyueming

Merge branch 'lym/text' of git.wanmeizhensuo.com:gengmeiios/GMBase into lym/text

* 'lym/text' of git.wanmeizhensuo.com:gengmeiios/GMBase:
  update

# Conflicts:
#	GMBase.podspec
chongtu
parents f18657e1 dd7e2e33
......@@ -569,6 +569,7 @@
SWIFT_OBJC_BRIDGING_HEADER = "GMBase/GMBase_Example-Bridging-Header.h";
SWIFT_OBJC_INTERFACE_HEADER_NAME = "$GMBase-Swift.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.2;
WRAPPER_EXTENSION = app;
};
name = Debug;
......@@ -590,6 +591,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "GMBase/GMBase_Example-Bridging-Header.h";
SWIFT_OBJC_INTERFACE_HEADER_NAME = "$GMBase-Swift.h";
SWIFT_VERSION = 4.2;
WRAPPER_EXTENSION = app;
};
name = Release;
......
......@@ -6,7 +6,7 @@
// Copyright © 2016年 wangyang. All rights reserved.
//
@import GMBase;
//@import GMBase;
#import "GMListViewModel.h"
@interface GMListViewController : WMBaseListViewController
......
......@@ -8,8 +8,9 @@ source 'git@git.wanmeizhensuo.com:gengmeiios/GMSpecs.git'
target 'GMBase_Example' do
pod 'GMBase', :path => '../'
# pod 'SnapKit', '4.2.0'
pod 'SnapKit', '4.2.0'
pod 'GMShareSDK', '0.2.1'
pod 'GMFoundation', :path => '../../GMFoundation'
pod 'GMPhobos', :git => 'git@git.wanmeizhensuo.com:gengmeiios/GMPhobos.git', :commit => '7e58199898627699373ad6a9f87b875ab04b0927'
target 'GMBase_Tests' do
......
......@@ -27,6 +27,7 @@ PODS:
- GMShareSDK
- MBProgressHUD
- SDWebImage
- SnapKit (= 4.2.0)
- "UITableView+FDTemplateLayoutCell (= 1.4)"
- GMCache (1.0.1):
- TMCache (= 2.1.0)
......@@ -100,10 +101,10 @@ PODS:
- Masonry (1.1.0)
- MBProgressHUD (0.9.2)
- MJExtension (3.2.1)
- MJRefresh (3.4.1)
- SDWebImage (5.7.3):
- SDWebImage/Core (= 5.7.3)
- SDWebImage/Core (5.7.3)
- MJRefresh (3.4.3)
- SDWebImage (5.8.0):
- SDWebImage/Core (= 5.8.0)
- SDWebImage/Core (5.8.0)
- SnapKit (4.2.0)
- TMCache (2.1.0)
- "UITableView+FDTemplateLayoutCell (1.4)"
......@@ -115,6 +116,7 @@ DEPENDENCIES:
- GMFoundation (from `../../GMFoundation`)
- "GMPhobos (from `git@git.wanmeizhensuo.com:gengmeiios/GMPhobos.git`, commit `7e58199898627699373ad6a9f87b875ab04b0927`)"
- GMShareSDK (= 0.2.1)
- SnapKit (= 4.2.0)
SPEC REPOS:
"git@git.wanmeizhensuo.com:gengmeiios/GMSpecs.git":
......@@ -159,7 +161,7 @@ SPEC CHECKSUMS:
AFNetworking: 5e0e199f73d8626b11e79750991f5d173d1f8b67
BDOpenSDKKit: 3fb530ce73f85a7d6ee69e7fd3d9158444c5bd09
DouyinOpenSDK: 5ba83de22963ba7a3ba70c8ff11dfcb2885ecc2b
GMBase: 2f05a06e886f8ea355e6f8be4276b667611140b4
GMBase: f48e18a07b654b31cf288dd07b3b7681f3046f07
GMCache: b78d8e46db864405e91d226ce640cc80d966c611
GMFoundation: 59cdf19ad5bdc479162da975cc739cf5cb418ab6
GMHud: 18d41f4900a204f27be14e9504fcee2060ae3b2c
......@@ -173,14 +175,14 @@ SPEC CHECKSUMS:
Masonry: 678fab65091a9290e40e2832a55e7ab731aad201
MBProgressHUD: 1569cf7ace17a8bac47aabfbb8580a49690386d1
MJExtension: 635f2c663dcb1bf76fa4b715b2570a5710aec545
MJRefresh: 3153c59a363159092c08b2177ec3a7d09f90bfaf
SDWebImage: 97351f6582ceca541ea294ba66a1fcb342a331c2
MJRefresh: 53e3e3219f204425ee6d3e62e8733d3295944cd6
SDWebImage: 84000f962cbfa70c07f19d2234cbfcf5d779b5dc
SnapKit: fe8a619752f3f27075cc9a90244d75c6c3f27e2a
TMCache: 95ebcc9b3c7e90fb5fd8fc3036cba3aa781c9bed
"UITableView+FDTemplateLayoutCell": 234e1582bcc4e18461af91155123bb96538ed030
WechatOpenSDK: 8b3ba4239193d1112205c139c94e21934e8f369a
Weibo_SDK: 5a4d08f7e1fedbb635435e4585c8c0439c7da089
PODFILE CHECKSUM: 78c2e567604571069245adf06b4c06623adb32cc
PODFILE CHECKSUM: 91fc775f851c4b233485f262092149bc6027c830
COCOAPODS: 1.9.1
......@@ -21,6 +21,9 @@ Pod::Spec.new do |s|
s.dependency 'SnapKit','4.2.0'
s.dependency 'GMShareSDK'
# s.dependency 'GMAlbum'
# SnapKit 4.2.0
s.dependency 'SnapKit', '4.2.0'
s.swift_version = '4.2'
s.static_framework = true
......
//
// GMBaseWebViewController.h
// ZhengXing
//
// Created by wangyang on 3/5/19.
// Copyright (c) 2019 Wanmei Creative. All rights reserved.
// 后期替代WMBaseViewController&WMBrowserViewController
#import "WMBaseViewController.h"
#import "GMClientH5Object.h"
//@import GMShareSDK;
#import <GMShareSDK/GMShareSDK.h>
#define kWebPhantom @"phantom"// 常用于H5新页面
#define kWebHybrid @"hybrid" // 常用于H5老页面
#import <GMShareSDK/GMShareView.h>
////#import "GMShareView.h"
#import <GMShareSDK/WMShareObject.h>
#import <GMShareSDK/GMDiaryShareView.h>
//#import <GMShareSDK/GMClientH5Object.h>
#import "GMWebViewModel.h"
typedef NS_ENUM(NSInteger, GMWebPageType) {
GMWebPageTypeNomal = 0,
GMWebPageTypeSign = 1, // 签到H5页面
GMWebPageTypeTopicDetail = 2,// 日记贴
GMWebPageTypeAnswer = 3,// 回答
GMWebPageTypeArticle = 4,// 话题
GMWebPageTypeSpecial = 5,// 专栏
GMWebPageTypeUserTopic = 6,// 用户贴
GMWebPageTypeQuestion = 7,// 回答 7.20 灰度用
GMWebPageTypeHospitalRank = 8,// 医院榜单
GMWebPageTypeDoctorRank = 9,// 医生榜单
};
@import GMKit;
@class GMWebViewComponent;
@interface GMBaseWebViewController : WMBaseViewController<GMClientH5BridgeDelegate> {
/**
* @brief 下面都是从js中得到的数据。其中_jsGlobalObject字典包含其它数据
*/
NSDictionary *_jsGlobalObject;
// 是否显示了分享
BOOL _isShowShare;
// 是否收藏
BOOL _isFavored;
// 是否是自己发的贴
BOOL _isPrivate;
// 是否是签到,签到导航栏透明,返回按钮、title颜色、rightIcon单独设置
BOOL _isSign;
}
@property (nonatomic, strong) GMWebViewComponent *webCompent;
/// web上数据处理
@property (nonatomic, strong) GMWebViewModel *viewModel;
/**
* @brief 要请求的 H5 url 除了 http://backend.dev.gengmei.cc/hybrid" 这部分后的path。比如一个h5是 http://backend.dev.gengmei.cc/hybrid/topic/3332214,那么path指需要赋值@"/topic/3332214"即可.
@note 在viewDidLoad前配置好。必须以"/"开头。重写moreQueryParameters可以添加额外query
*/
@property (nonatomic, strong) NSString *path;
/**
* @brief 对于从服务器那儿获取到的完整H5 url,使用该属性。
@note 在viewDidLoad前配置好。会覆盖path属性。重写moreQueryParameters可以添加额外query
*/
@property (nonatomic, strong) NSString *fullURL;
/// 通过webPageType 页面不同设置不同的差异性
@property (nonatomic, assign) GMWebPageType webPageType;
#pragma mark - 分享
@property (nonatomic, strong) GMShareView *shareView;
@property (nonatomic, strong) GMDiaryShareView *diaryShareView;
/*** @brief 收藏url**/
@property (nonatomic,strong) NSString *favUrl;
/*** @brief 从_jsGlobalObject中获取的分享Model */
@property (nonatomic, strong) WMShareObject *shareObject;
/*** @brief 日记分享Model数组 */
@property (nonatomic, strong) NSMutableArray *diaryShareArr;
/*** @brief 微信分享Model */
@property (nonatomic, strong) WMShareObject *weixinShareObject;
/*** @brief 分享的配置 */
@property (nonatomic, strong) GMShareConfigObject *shareConfigObject;
@property (nonatomic , strong) NSString *favorType;
/**
设置打开的权限类型
*/
@property (nonatomic, assign) NSInteger settingType;
@property (nonatomic, assign) BOOL backNeedRefresh;
/**
* @brief 重写该方法,为fullURL在请求前添加更多参数。必须以 & 开头
* 原方法只返回了空字符串,不需要call super
*
* @return 要额外添加的参数。如:&key1=value&key2=value
*/
- (NSString *)moreQueryParameters;
/**
调用该方法以重新构造URL并且[_webView loadRequest:request];
*/
- (void)reloadURL;
/**
处理请求URL
*/
- (void)handleURL;
// 一般情况下 页面刷新时候调用
- (void)refreshWebView;
// 本地获取通用数据
- (NSString *)nativeCommonParam;
@end
//
// WMDiaryAndTopicBaseController.m
// ZhengXing
//
// Created by wangyang on 3/5/15.
// Copyright (c) 2015 Wanmei Creative. All rights reserved.
//
#import <MessageUI/MessageUI.h>
#import "GMBaseWebViewController.h"
//#import "AppDelegate+AppInit.h"
//#import "Gengmei-Swift.h"
#import "UIViewController+UrlScheme.h"
#import "WMBaseViewController+OCNavigationBar.h"
#import <mach/mach_time.h>
//#import "GMBase-Swift.h"
//#import "GMCookieManager.h"
//#import "GMWebViewUrlProtocol.h"
//#import <GMShareSDK/GMWeixinShareView.h>
#import <GMShareSDK/WMShareObject.h>
//#import "GMBase-prefix.pch"
//#import "GMCommonAlertView.swift"
//#import "GMWebViewComponent.swift"
//TODO: 待解决
//GMPhotoPickDismissDelegate
//GMCommonAlertViewDelegate
//MFMessageComposeViewControllerDelegat
@interface GMBaseWebViewController ()<UIWebViewDelegate, GMShareViewDelegate, GMDiaryShareViewDelegate>
{
// 是否显示微信快照和朋友圈快照
BOOL _isShowScreenshot;
//TODO: 待思考
// GMAddressManager *_manager;
// 是否需要回调权限打开状态
BOOL _isSettingCallback;
// 表示要上传的照片是可以公开的还是具体保护性的
BOOL _isPrivatePhoto;
// 接受h5的参数,图片上传成功后,以这个参数为key,把图片Url返回给h5
NSString *_requestCoder;
// 是否显示了来自h5设置的rightButton
BOOL _isJsRightButton;
BOOL _isJsNearRightButton;
// 导航栏是否透明,YES透明,NO不透明
BOOL _isNavigationAlpha;
// 导航栏是否隐藏
BOOL _isNavigationHidden;
}
@property (nonatomic, assign) CGFloat animationDistance;
//TODO: 待思考
//@property (nonatomic, strong) GMPlayerView *playBackView;
@property (nonatomic, assign) BOOL goToAppSettingsPage;// 跳转到系统设置页面
@end
@implementation GMBaseWebViewController
#pragma mark - init
- (void)initController {
[super initController];
self.viewModel = [GMWebViewModel new];
// self.goToAppSettingsPage = NO;
self.webPageType = GMWebPageTypeNomal;
// 短信链接唤起app埋点 @author 李震(WMBrowserViewController)
//TODO: 待处理
// if ([AppDelegate shareInstance].extraParam.isNonEmpty) {
// self.extraParam = [AppDelegate shareInstance].extraParam;
// [AppDelegate shareInstance].extraParam = @"";
// }
}
#pragma mark - view lifeCycle
- (void)viewDidLoad {
[super viewDidLoad];
[self initReferer];
[self initRefererLink];
[self initReferrerTabName];
self.navigationBar.isShowShadow = NO;
self.backNeedRefresh = NO;
CGFloat top = OCNavigationBar.barHeight;
[self.webCompent mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.mas_equalTo(0);
make.top.mas_equalTo(top);
make.bottom.mas_equalTo(0);
}];
// 设置Agent,关键字是最后的那个Gengmei,这样服务端就知道是通过app内部加载网页。
NSDictionary *dictionary = USER_AGENT_DIC;
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
// 加载URL
[self reloadURL];
// 添加通知监听
[self addActiveObserver];
// 导航栏渐变
[self prepareNavigation];
}
/// 通过webPageType 页面不同设置不同的差异性
/// @param webPageType webPageType
- (void)setWebPageType:(GMWebPageType)webPageType {
_webPageType = webPageType;
switch (webPageType) {
case GMWebPageTypeSign:
self.pageName = @"new_sign";
break;
case GMWebPageTypeQuestion:
{
self.pageName = @"question_answer_detail";
}
break;
default:
break;
}
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self nativeAppearToCallJS];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (self.backNeedRefresh) {
[self refreshWebView];
self.backNeedRefresh = NO;
}
[self nativeDisAppearToCallJS];
}
#pragma mark - Load Request
- (void)reloadURL {
[self handleURL];
[self webViewLoadRequest];
}
- (void)webViewLoadRequest {
if (self.fullURL == nil || [self.fullURL isEqualToString:@""]) {
return;
}
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
self.webCompent.fullUrl = self.fullURL;
// self.webCompent.fullUrl = @"http://172.30.8.83:3000/phantom/question/3482021";
[self.webCompent webviewLoad:self];
}
// 一般情况下 页面刷新时候调用
- (void)refreshWebView {
//自己本地调用webview刷新时候,绑定关系还存在,不需要重新绑定GMClient和window上的方法.
[self.webCompent reload];
}
#pragma mark - Handle URL
/**
不允许重写
*/
- (void)handleURL {
if (_fullURL.length == 0) {
// 使用path拼接,并且加上query
_fullURL = [self wrapWebUrlWithPath];
} else {
// 为fullURL加上默认query
_fullURL = [self wrapWebUrlWithFullURL];
}
if (![_fullURL isNonEmpty]) return;
// 额外的参数
_fullURL = [_fullURL stringByAppendingString:[self moreQueryParameters]];
/// 添加referrer_link
_fullURL = [self addReferrerLinkWithFullURL];
self.webCompent.fullUrl = _fullURL;
}
/**
不允许重写
*/
- (NSString *)wrapWebUrlWithPath {
if (![_path isNonEmpty]) {
return @"";
}
NSString *path = self.path;
NSString *parames = [NSString stringWithString:GMNetworking.urlCommonParameters];
if ([path containsString:@"?"]) {
parames = [parames stringByReplacingOccurrencesOfString:@"?" withString:@"&"];
}
NSString *wrapedUrl = [NSString stringWithFormat:@"%@%@%@", GMServerDomains.apiHost, path,parames];
// 兼容新老页面,在此认为新的没有host域名的h5页面默认携带phantom,而不进行拼接
NSArray *pathArray = [path componentsSeparatedByString:@"/"];
if (![pathArray containsObject:kWebPhantom] && ![pathArray containsObject:kWebHybrid]) {
wrapedUrl = [NSString stringWithFormat:@"%@/%@%@%@", GMServerDomains.apiHost, kWebHybrid, path, parames];
}
return wrapedUrl;
}
/**
不允许重写
*/
- (NSString *)wrapWebUrlWithFullURL {
// 因为有的 fullURL 带了一部分 query,而将要拼接的urlCommonParameters还带了一个问号,所以要做判断
NSString *defaultQuery = GMNetworking.urlCommonParameters;
if ([_fullURL rangeOfString:@"?"].length > 0) {
defaultQuery = [defaultQuery stringByReplacingOccurrencesOfString:@"?" withString:@"&"];
}
NSString *wrapedUrl = [NSString stringWithFormat:@"%@%@", _fullURL, defaultQuery];
return wrapedUrl;
}
/// 添加referrer_link 不允许重写
- (NSString *)addReferrerLinkWithFullURL {
NSString *referrerLink = @"";
NSDictionary *param = [_fullURL urlQueryToDictionary];
if (![param.allKeys containsObject:@"referrer_link"]) {
BOOL aiConsultGray = GMLaunchManager.shareManager.appConfigObject.aiConsultGray;
NSString *referrerLinkString = [self.referrerLink componentsJoinedByString:@","];
referrerLink = [NSString stringWithFormat:@"&ai_consult_gray=%@&referrer_link=%@",(aiConsultGray ? @"1" : @"0"),referrerLinkString];
}
return [NSString stringWithFormat:@"%@%@", _fullURL, referrerLink];
}
- (NSString *)moreQueryParameters {
return @"";
}
- (void)setFullURL:(NSString *)fullURL {
_fullURL = fullURL;
debugLog(@"%@", _fullURL);
NSDictionary *params = [fullURL urlQueryToDictionary];
if ([params.allKeys containsObject:@"referrer"]) {
self.referer = params[@"referrer"];
}
// cpc 相关
if ([params.allKeys containsObject:@"cpc_referer"]) {
self.cpc_referer = [params[@"cpc_referer"] integerValue];
}
if ([params.allKeys containsObject:@"is_cpc"]) {
self.is_cpc = [params[@"is_cpc"] boolValue];
}
// navigation_color_clear: 1透明,0不透明
if ([params[@"navigation_color_clear"] intValue]) {
_isNavigationAlpha = YES;
// referer: push:表示来源为推送;pop_ad:表示来源开屏小广告(没有倒计时);big_ad:表示来源开屏大广告(有倒计时)
self.navigationBar.leftIcon = @"back_circle_white";
self.navigationBar.buttonMargin = 10;
}
// 设置导航栏是否隐藏
_isNavigationHidden = [params[@"navigation_hidden"] boolValue];
}
#pragma mark - 分享 GMShareViewDelegate
- (void)willShowShareView:(GMShareView *)shareView {
shareView.hasFav = _isFavored;
shareView.showDelete = _isPrivate;
shareView.showScreenshot = _isShowScreenshot;
// 连续签到,补签分享,隐藏复制链接、举报、刷新
shareView.showReport = ![_shareConfigObject.hideReport boolValue];
shareView.showCopyLink = ![_shareConfigObject.hideCopyLink boolValue];
shareView.showRefresh = ![_shareConfigObject.hideRefresh boolValue];
if ([_shareConfigObject.hideReport boolValue] && [_shareConfigObject.hideCopyLink boolValue] && [_shareConfigObject.hideRefresh boolValue]) {
shareView.topLineView.hidden = YES;
} else {
shareView.topLineView.hidden = NO;
}
shareView.taskType = _shareConfigObject.taskType;
shareView.isReportShareResult = _shareConfigObject.isReportShareResult;
shareView.shareObject = _shareObject;
}
- (NSString *)shareViewNeedBusinessId {
return self.businessId;
}
- (void)shareResponseSuccess {
[self.webCompent.webView evaluateJavaScript:_shareConfigObject.shareCallback completionHandler:nil];
}
/**@brief 获取分享内容的协议方法需在子类实现,因为需要定制,删除和收藏的协议方法在子类实现即可*/
- (void)shareView:(GMShareView *)shareView favriteContentWithIndexPath:(NSIndexPath *)indexPath {
if ([[GMLoginManager shareInstance] showLoginViewIfNeeded]){
return;
}
GMHTTPMethod method = _isFavored ? GMHTTPMethodDelete : GMHTTPMethodPost;
__weak __typeof(self)weakSelf = self;
[GMNetworking requestOCWithApi:self.favUrl method:method parameters:nil completion:^(GMResponseOC * _Nonnull responseObject) {
if (responseObject.isSuccess) {
_isFavored = !_isFavored;
shareView.hasFav = _isFavored;
NSString *action;
if (_isFavored) {
action = @"do";
[weakSelf showComplete:@"收藏成功"];
}else{
action = @"undo";
[weakSelf showComplete:@"取消收藏成功"];
}
// 分享的埋点
NSDictionary *dic = @{@"action": action,
@"type": weakSelf.favorType,
@"business_id": weakSelf.businessId};
[Phobos track:@"favor" attributes:dic];
[shareView.shareCollectionView reloadItemsAtIndexPaths:@[indexPath]];
} else {
[weakSelf showWarning:responseObject.message];
}
}];
}
#pragma mark - GMShareViewDelegate
- (void)copyShareUrl{
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
if ([_shareObject.url isNonEmpty]) {
pasteboard.string = _shareObject.url;
[self toast:@"链接已复制到系统粘帖板"];
}
}
- (NSMutableDictionary *)fetchSharePublishContent:(GMSharePlatform)shareType{
//这里时间是native,所以只能弹普通的大分享
id shareImage = nil;
GMShareContentType contentType = GMShareContentTypeAuto;
WMShareBasicObject * object = [WMShareBasicObject new];
NSString *image = _shareObject.image;
if (image.length != 0) {
shareImage = [GMShareSDK compressWithUrl:image];
}else{
// 使用app logo做图标
shareImage = [UIImage imageNamed:@"icon"];
}
// 微信会话分享且微信小程序内容不为空的时候,认为是微信小程序分享
if (shareType == GMSharePlatformWechatSession && [_shareObject.wechatmini.path isNonEmpty]) {
shareType = GMSharePlatformWechatMiniProgram;
}
NSString *channel = @"";
switch (shareType) {
case GMSharePlatformWechatSession:
object = _shareObject.wechat;
channel = @"wechat";
break;
case GMSharePlatformWechatTimeline:
object = _shareObject.wechatline;
channel = @"wechatline";
break;
case GMSharePlatformQQFriend:
object = _shareObject.qq;
channel = @"qq";
break;
case GMSharePlatformQQSpace:
object = _shareObject.qq;
channel = @"qzone";
break;
case GMSharePlatformSinaWeibo:
object = _shareObject.weibo;
channel = @"tsina";
break;
case GMSharePlatformWechatSessionSnapShot:
object = _shareObject.wechatScreenshot;
contentType = GMShareContentTypeImage;
//这里不能压缩图片,要保证质量分享
shareImage = _shareObject.wechatScreenshot.content;
break;
case GMSharePlatformWechatTimelineSnapShot:
object = _shareObject.wechatlineScreenshot;
shareImage = _shareObject.wechatlineScreenshot.content;
contentType = GMShareContentTypeImage;
break;
default:
break;
}
if (_isSign) {
if ([_shareObject.url containsString:@"?"]) {
_shareObject.url = [NSString stringWithFormat:@"%@&referrer=%@",_shareObject.url, channel];
} else {
_shareObject.url = [NSString stringWithFormat:@"%@?referrer=%@",_shareObject.url, channel];
}
}
NSMutableDictionary *shareParams = [NSMutableDictionary dictionary];
if (shareType == GMSharePlatformWechatMiniProgram){
[shareParams shareSetupMiniProgramShareParamsByUrl:_shareObject.url
userName:_shareObject.wechatmini.userName
path:_shareObject.wechatmini.path
title:_shareObject.wechatmini.title
description:_shareObject.wechatmini.desc
thumbImage:_shareObject.wechatmini.thumbImageUrl
hdImageData:_shareObject.wechatmini.hdImageUrl];
} else {
[shareParams shareSetupShareParamsByText:object.content
images:shareImage
url:[NSURL URLWithString:_shareObject.url]
title:object.title
type:contentType];
}
return shareParams;
}
#pragma mark - GMClientH5BridgeDelegate
/**
* @brief pageData
*/
- (void)jsGlobalDataLoaded:(NSString *)jsonString {
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
_jsGlobalObject = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
if (_jsGlobalObject == nil) {
return;
}
// 从H5中取得全局变量
@try {
// JIRA 上曾有一个关于此处的bug上报,因为无法查明原因,所以加try catch
[self.webCompent.webView evaluateJavaScript:@"window.GLOBAL.pagedata" completionHandler:nil];
// 当前版本对h5返回businessid和pageName的处理,只在commonwebview中处理,basewebview中不处理
} @catch (NSException *exception) {
// [Bugly reportException:[NSException exceptionWithName:@"_jsGlobalObject获取异常" reason:exception.reason userInfo:@{@"exceptionInfo": exception.userInfo, @"url": self.fullURL}]];
}
if (_jsGlobalObject[@"page_name"]) {
self.pageName = _jsGlobalObject[@"page_name"];
}
if ([_jsGlobalObject[@"business_id"] isNonEmpty]) {
self.businessId = SafeString(_jsGlobalObject[@"business_id"]);
}
if ([_jsGlobalObject.allValues containsObject:@"back_need_refresh"]) {
_backNeedRefresh = [_jsGlobalObject[@"back_need_refresh"] boolValue];
}
// 是否收藏
_isFavored = [_jsGlobalObject[@"is_favord"] boolValue];
// 是否是自己的帖子
_isPrivate = [_jsGlobalObject[@"is_private"] boolValue];
//分享数据源
_shareObject = [[WMShareObject alloc] initWithDictionary:_jsGlobalObject[@"share_data"] error:nil];
_shareConfigObject = [[GMShareConfigObject alloc] initWithDictionary:_jsGlobalObject[@"share_config"] error:nil];
//同时不为空的时候才显示微信快照和朋友圈快照
_isShowScreenshot = [_shareObject.wechatScreenshot.content isNonEmpty] && [_shareObject.wechatScreenshot.content isNonEmpty];
// 是否隐藏分享按钮
if ([_jsGlobalObject.allKeys containsObject:@"hide_share"] &&
![_jsGlobalObject[@"hide_share"] boolValue] && _shareObject) {
_isShowShare = YES;
} else {
_isShowShare = NO;
}
_isSign = [_jsGlobalObject[@"navigation"][@"nav_type"] isEqualToString:@"sign"];
// 连续补签,分享日记
if ([_jsGlobalObject[@"topic_share_data"] count]) {
self.diaryShareArr = [NSMutableArray array];
[self.diaryShareArr addObjectsFromArray:[GMDiaryShareObject arrayOfModelsFromDictionaries:_jsGlobalObject[@"topic_share_data"] error:NULL]];
}
// 处理导航栏数据
[self dealNavigationData];
}
#pragma mark - Deal Navigation
// 导航栏隐藏显示
- (void)jsControlTitleBarVisible:(NSString *)jsonString {
NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *showDic = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableLeaves
error:nil];
if ([showDic[@"show"] boolValue]) {
if (!_isSign) {
self.navigationBar.backgroundColor = [UIColor whiteColor];
self.navigationBar.isShowShadow = YES;
} else {
self.navigationBar.backgroundColor = [UIColor clearColor];
}
} else {
self.navigationBar.backgroundColor = [UIColor.blackColor colorWithAlphaComponent:0.6];
self.navigationBar.isShowShadow = NO;
}
}
// 设置导航数据
- (void)dealNavigationData {
NSDictionary *navDict = _jsGlobalObject[@"navigation"];
if (navDict) {
// 右侧图标
NSString *rightIcon = navDict[@"right_button"];
if (rightIcon.isNonEmpty) {
self.navigationBar.rightIconURL = rightIcon;
}
// 右侧文案
NSString *rightText = navDict[@"right_text"];
if (rightText.isNonEmpty) {
self.navigationBar.rightTitle = rightText;
}
self.navigationBar.rightButton.hidden = _isNavigationAlpha;
// 签到
if (_isSign) {
[self.navigationBar.rightButton mas_updateConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(0);
}];
}
// 设置导航栏是否透明
if ([navDict.allKeys containsObject:@"navigation_color_clear"]) {
_isNavigationAlpha = [navDict[@"navigation_color_clear"] intValue] ? YES : NO;
}
self.animationDistance = [navDict[@"header_height"] intValue];
// 设置导航栏是否隐藏
_isNavigationHidden = [navDict[@"navigation_hidden"] boolValue];
// 设置侧滑手势禁用
self.fd_interactivePopDisabled = [navDict[@"pop_disabled"] boolValue];
}
// 设置导航栏
[self prepareNavigation];
// 设置导航栏Title
[self setupNavigateTitle];
}
/// 设置导航栏Title
- (void)setupNavigateTitle {
// 设置导航栏
NSString *title = [_jsGlobalObject[@"name"] isNonEmpty] ? _jsGlobalObject[@"name"] : self.title;
if (_isShowShare) {
[self setNavigateTitle:title rightButtonOption:OCBarButtonImageTypeShare];
} else {
[self setNavigateTitle:title rightButtonOption:OCBarButtonImageTypeDefault];
}
}
/// 设置导航栏是否隐藏
- (void)prepareNavigation {
// navigation_color_clear: 1透明,0不透明
CGFloat top = (_isNavigationAlpha || _isNavigationHidden)?0:OCNavigationBar.barHeight;
if (_isNavigationAlpha) {
self.navigationBar.leftIcon = @"back_circle_white";
self.navigationBar.buttonMargin = 10;
self.webCompent.webView.scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
self.webCompent.webView.scrollView.delegate = self;
[self scrollViewDidScroll:self.webCompent.webView.scrollView];
}
[self.webCompent mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(top);
}];
self.navigationBar.hidden = _isNavigationHidden;
}
/// 前端调用客户端方法进行返回操作
- (void)jsPopViewControllerAnimated:(BOOL)animated {
if ([self.parentViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navigation = (UINavigationController *)self.parentViewController;
NSArray *controllers = navigation.viewControllers;
if (self.presentingViewController && controllers.count == 1) {
[self dismissViewControllerAnimated:YES completion:nil];
} else {
[self.navigationController popViewControllerAnimated:YES];
}
} else {
[self dismissViewControllerAnimated:YES completion:nil];
}
}
#pragma mark - Deal Gload
/**
* @brief js调用该方法以hideLoading
*/
- (void)loadDomFinished {
[self hideLoading];
// 因为此时_jsGlobalObject还不能从H5中获取,所以只先设置一个title,与数据相关的分享功能先不展示
// self.title = [self.webCompent.webView evaluateJavaScript:@"document.title" completionHandler:nil];
[self.webCompent.webView evaluateJavaScript:@"document.title" completionHandler:^(id resonse, NSError * _Nullable error) {
NSLog(@"%@",resonse);
}];
}
- (void)jsShowLoading{
[self showLoading:nil];
}
- (void)jsHideLoading{
[self hideLoading];
}
- (void)jsLogout {
[[GMLoginManager shareInstance] doLogoutAndShowLoginView];
}
// 显示空白页面
- (void)jsShowNativeEmptyView {
[self showEmptyView:GMEmptyViewTypeException];
}
- (void)emptyViewDidClickReload {
[Phobos track:@"on_click_button" attributes:@{@"page_name": SafeString(self.pageName),
@"button_name": @"click_reload"}];
[self hideEmptyView];
[self refreshWebView];
}
// 网络状态 2: 其他 1:wifi 0:无网络
- (NSInteger)jsCheckNetworkState {
NSInteger networkState = 0;
if ([AFNetworkReachabilityManager sharedManager].isReachable) { // 联网状态
if ([AFNetworkReachabilityManager sharedManager].reachableViaWiFi == NO) { // 非WiFi
networkState = 2;
} else {
networkState = 1;
}
}
#warning h5
NSString *javaScriptStr = [NSString stringWithFormat:@"window.gm.pack.run('jsCheckNetworkStateCallback',%zd)",networkState];
[self.webCompent.webView evaluateJavaScript:javaScriptStr completionHandler:nil];
return networkState;
}
- (void)jsLocationShowAlertIfNotAllowed {
[GMLocationManager showAlertIfNotAllowed];
}
#pragma mark - ShareView
- (void)jsObjShowShareViewWithJSONString:(NSString *)JSONString{
if ([JSONString isNonEmpty]) {
_shareObject = [[WMShareObject alloc] initWithString:JSONString error:nil];
}
[self.shareView showWithShareUrl:_shareObject.url];
[self addShareTopView:self.shareView.topView];
}
- (void)jsObjShowDiaryShareViewWithJSONString:(NSString *)JSONString {
if ([JSONString isNonEmpty]) {
self.diaryShareArr = [NSMutableArray array];
NSData *data = [JSONString dataUsingEncoding:NSUTF8StringEncoding];
NSArray *shareArr = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
[self.diaryShareArr addObjectsFromArray:[GMDiaryShareObject arrayOfModelsFromDictionaries:shareArr error:NULL]];
}
[self.diaryShareView showWithShareArr:self.diaryShareArr];
[self addShareTopView:self.diaryShareView.topView];
}
- (void)addShareTopView:(UIView *)topView {
// 连续签到,补签标题
[(GMShareTopView *)topView setName:_shareConfigObject.shareTitle title:_shareConfigObject.shareInfo subTitle:_shareConfigObject.shareTip];
if ([_shareConfigObject.shareTitle isNonEmpty] || [_shareConfigObject.shareInfo isNonEmpty] || [_shareConfigObject.shareTip isNonEmpty]) {
_shareView.topView.hidden = NO;
} else {
_shareView.topView.hidden = YES;
}
}
- (void)jsShowWXShareViewWithJSONString:(NSString *)JSONString{
if ([JSONString isNonEmpty]) {
_weixinShareObject = [[WMShareObject alloc] initWithString:JSONString error:nil];
}
if (_weixinShareObject != nil) {
//TODO: GMWeixinShareView 待考虑
// GMWeixinShareView * weiXinShareView = [GMWeixinShareView shareView];
// weiXinShareView.weixinShareObject = _weixinShareObject;
// weiXinShareView.sourceController = self;
// [self.view addSubview:weiXinShareView];
// [weiXinShareView mas_makeConstraints:^(MASConstraintMaker *make) {
// make.edges.equalTo(self.view).insets(UIEdgeInsetsZero);
// }];
// [weiXinShareView layoutIfNeeded];
// [weiXinShareView showShareView:nil];
}
}
// 根据type 展示跳转指定分享平台(V7.16.1)
- (void)jsSharewithType:(NSDictionary *)data {
NSString *type = data[@"type"]?:@"Wechat";
self.shareObject = [[WMShareObject alloc] initWithDictionary:data[@"share_data"] error:nil];
GMSharePlatform shareType = GMSharePlatformWechatTimeline;
if ([type isEqualToString:@"QZone"]) {
shareType = GMSharePlatformQQSpace;
}else if ([type isEqualToString:@"QQ"]) {
shareType = GMSharePlatformQQFriend;
}else if ([type isEqualToString:@"Wechat"]) {
shareType = GMSharePlatformWechatSession;
}else if ([type isEqualToString:@"WechatMoments"]) {
shareType = GMSharePlatformWechatTimeline;
}else if ([type isEqualToString:@"SinaWeibo"]) {
shareType = GMSharePlatformSinaWeibo;
}
self.shareView.shareUrl = self.shareObject.url;
[self.shareView shareWithType:shareType];
}
// 根据type 展示跳转指定分享平台(兼容之前的代码)
- (void)jsShare:(NSString *)shareDataString withType:(NSString *)type {
NSData *shareData = [shareDataString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *data = [NSJSONSerialization JSONObjectWithData:shareData options:NSJSONReadingAllowFragments error:NULL];
if ([type isNonEmpty]) {
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:data];
dict[@"type"] = type;
data = dict;
}
[self jsSharewithType:data];
}
/*** 回放 */
- (void)jsPlayVideo:(NSString *)JSONString {
if (![JSONString isNonEmpty]) {
[self toast:@"视频无法播放"];
return;
}
NSData *data = [JSONString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:NULL];
NSString *playFrom = jsonDict[@"page_name"];
NSString *topicId = jsonDict[@"topic_id"];
NSString *businessId = jsonDict[@"business_id"];
NSString *cardType = jsonDict[@"card_type"];
NSInteger index = [jsonDict[@"index"] integerValue];
CGFloat currentTime = [jsonDict[@"currentTime"] floatValue];
NSInteger state = [jsonDict[@"state"] integerValue];
GMVideoObject *video = [GMVideoObject new];
video.businessId = SafeString(businessId);
video.cardType = SafeString(cardType);
video.pageName = SafeString(playFrom);
_playBackView = [[GMPlayerView alloc] init];
_playBackView.topicId = SafeString(topicId);
_playBackView.from = SafeString(playFrom);
_playBackView.video = video;
_playBackView.needSkipSeconds = currentTime;
_playBackView.index = index;
_playBackView.playState = state;
NSString *playUrl = jsonDict[@"url"];
[_playBackView play:playUrl animationRect:CGRectZero];
}
/**
获取用户通讯录
@author zhaiguojun 16-09-21 in 6.3.2
@since 6.4.1
*/
- (void)jsGetAddressBook {
dispatch_async(dispatch_get_main_queue(), ^{
_manager = [GMAddressManager new];
[_manager getAddressBookAuthorization];
});
}
/**
弹出通讯录供用户选择
@author zhaiguojun 16-09-28 in 6.4.1
*/
- (void)jsChooseOneContactPerson:(NSString *)key {
_manager = [GMAddressManager new];
__weak __typeof(self)weakSelf = self;
_manager.getOneContactPersonBlock = ^(NSDictionary *result){
NSData *jsParamData = [NSJSONSerialization dataWithJSONObject:@{key:result} options:0 error:NULL];
NSString *jsParam = [[NSString alloc] initWithData:jsParamData encoding:NSUTF8StringEncoding];
NSString *jsString = [NSString stringWithFormat:@"gm.util.setContactPerson('%@')",jsParam];
[weakSelf.webCompent.webView evaluateJavaScript:jsString completionHandler:nil];
};
[_manager chooseContactPersonAddressBookJsonString];
}
#pragma mark - AlertView
- (void)jsShowTaskAlert:(NSString *)extra {
NSData *data = [extra dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *extraDic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
if (extraDic == nil) {
return;
}
[AppDelegate.shareInstance showPointAlert:extraDic];
}
- (void)jsShowAlertViewWithJSONString:(NSString *)JSONString {
WMAlertParameterObject *object = nil;
if ([JSONString isNonEmpty]) {
object = [[WMAlertParameterObject alloc] initWithString:JSONString error:nil];
}
__weak typeof(self)weakSelf = self;
NSString *title = object.title?:@"标题";
NSString *content = object.content?:@"内容";
NSString *confirmText = object.confirmText?:@"确定";
NSString *confirmCallback = object.confirmCallback?:@"";
UIAlertController *alert = [UIAlertController showCustomAlertWithTitle:title message:content];
[alert addAction:confirmText actionHandler:^{
[weakSelf.webCompent.webView evaluateJavaScript:confirmCallback completionHandler:nil];
}];
}
- (void)jsShowConfirmViewWithJSONString:(NSString *)JSONString{
WMAlertParameterObject *object = nil;
if ([JSONString isNonEmpty]) {
object = [[WMAlertParameterObject alloc] initWithString:JSONString error:nil];
}
NSString *title = object.title?:@"标题";
NSString *content = object.content?:@"内容";
NSString *confirmText = object.confirmText?:@"确定";
NSString *cancelText = object.cancelText?:@"取消";
NSString *confirmCallback = object.confirmCallback?:@"";
NSString *cancelCallback = object.cancelCallback?:@"";
__weak typeof(self)weakSelf = self;
UIAlertController *alert = [UIAlertController showCustomAlertWithTitle:title message:content];
[alert addAction:confirmText actionHandler:^{
[weakSelf.webCompent.webView evaluateJavaScript:confirmCallback completionHandler:nil];
}];
[alert addAction:cancelText actionHandler:^{
[weakSelf.webCompent.webView evaluateJavaScript:cancelCallback completionHandler:nil];
}];
}
- (void)jsShowToastWithJSONString:(NSString *)JSONString{
WMToastParameterObject *object = nil;
if ([JSONString isNonEmpty]) {
object = [[WMToastParameterObject alloc] initWithString:JSONString error:nil];
}
[self toast:SafeValue(object.text)];
}
#pragma mark - JumpToOtherPage
- (void)jsOpenBrowser:(NSString *)url{
UIAlertController *alert = [UIAlertController showCustomAlertWithTitle:@"提示" message:@"你访问的网址将以外部浏览器打开,是否继续?"];
[alert addAction:@"否" actionHandler:nil];
[alert addAction:@"是" actionHandler:^{
NSURL *browserUrl = [NSURL URLWithString:url];
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
[[UIApplication sharedApplication] openURL:browserUrl options:@{} completionHandler:NULL];
} else {
[[UIApplication sharedApplication] openURL:browserUrl];
}
}];
}
// 调起第三方APP 比如 爱奇艺 7.15.1
- (void)jsSkipToThirdApp:(NSString *)jsonString {
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
NSURL *url = [NSURL URLWithString:dic[@"target_url"]];
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"10.0")) {
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:NULL];
} else {
[[UIApplication sharedApplication] openURL:url];
}
}
// 跳转到设置页面
- (void)jsJumpToLocationSettings {
[GMLocationManager jumpToSettings];
}
// 调用打电话
- (void)jsCallPhone:(NSString *)phone {
NSString *phoneStr = [NSString stringWithFormat:@"tel:%@",phone];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString: phoneStr]];
}
// 发短信
- (void)jsSendMessage:(NSString *)phone withBody:(NSString *)body {
if ([GMMessageController canSendText]) {
GMMessageController *messageVc = [[GMMessageController alloc] init];
messageVc.messageComposeDelegate = self;
messageVc.recipients = @[phone];
messageVc.body = body;
#warning ios 13
messageVc.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:messageVc animated:YES completion:nil];
} else {
[self toast:@"当前设备不支持发短信"];
}
}
/*!
* @author zhaiguojun, 16-07-05
*
* @brief 选择图片上传,然后把返回的URL返回给前端
*
* @param requestCode 传过来的标识
*
* @since 6.2.0
*/
- (void)openAlbum:(NSString *)requestCode isPrivate:(BOOL)isPrivate{
_requestCoder = requestCode;
_isPrivatePhoto = isPrivate;
GMPhotoPickController *controller = [[GMPhotoPickController alloc] initWithMaxImageCount:1 maxVideoCount:0 maxCount:1 photoDisplayType:GMPhotosDisplayImageType];
controller.dismissDelegate = self;
controller.root.singleSelection = YES;
#warning ios 13
controller.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:controller animated:YES completion:NULL];
}
- (void)hintGotoSetting {
UIAlertAction *action = [UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleCancel handler:nil];
UIAlertAction *gotoAction = [UIAlertAction actionWithTitle:@"去设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self goToAppSystemSettings];
}];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"温馨提示" message:@"请您先去设置允许APP访问您的相机 设置>隐私>相机" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:action];
[alert addAction:gotoAction];
[self presentViewController:alert animated:YES completion:nil];
}
/// 保险状态返回
/// @param dict has_bought: true(确定购买) / false(取消购买)
- (void)jsInsurancePurchase:(NSDictionary *)dict {
//可以考虑废弃 在GMInsuranceWebviewController做了处理 避免其他类用到这个方法因此先保存着
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:REFRESH_SETTLEMENT_LIST object:nil userInfo: dict];
[self.navigationController popViewControllerAnimated:YES];
});
}
#pragma mark - MFMessageComposeViewControllerDelegate
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result {
[controller dismissViewControllerAnimated:true completion:nil];
}
#pragma mark - local Data
- (void)jsSetLocalStorage:(NSString *)key withStorage:(NSString *)value {
if (![value isNonEmpty]) {
value = @"";
}
[GMCache storeObjectAtDocumentPathWithkey:key object:value];
}
- (NSString *)jsGetLocalStorage:(NSString *)key {
NSString *cacheKey = [GMCache fetchObjectAtDocumentPathWithkey:key];
#warning h5
NSString *javaScriptStr = [NSString stringWithFormat:@"window.gm.pack.run('getLocalStorage',%@)",cacheKey];
[self.webCompent.webView evaluateJavaScript:javaScriptStr completionHandler:nil];
if (![cacheKey isNonEmpty]) {
return @"";
}
return cacheKey;
}
- (void)jsSyncSSOInfo:(NSString *)jsonString {
NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *info = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
if (info[@"user_id"] != nil) {
[[GMLoginManager shareInstance] loginSuccessWithUserInfo:info shouldBroadcast:NO];
}
if (info[@"cookie"] != nil && info[@"domain"] != nil) {
//TODO:
// [GMCookieManager saveSessionId:info[@"cookie"] domain:info[@"domain"]];
}
}
- (void)jsNewbieCouponGot:(NSInteger)flag {
[GMCache storeObjectAtMemoryWithkey:kNewUserTicketHasGot object:@(flag)];
}
/**
* @author wangjun, 16-07-04 14:07:51
*
* 秒杀页面添加到系统日历事件
* @param jsonString H5传来的的美购信息
*/
- (void)jsRemindEvent:(NSString *)jsonString {
NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:NULL];
NSInteger beginTime = [json[@"start_time"] longValue];
NSInteger endTime = [json[@"end_time"] longValue];
NSString *title = json[@"title"];
NSString *url = json[@"url"];
NSString *serviceId = json[@"service_id"];
BOOL notify = [json[@"notify"] boolValue];
GMCalendarEventManager *manager = [[GMCalendarEventManager alloc] init];
__weak typeof(manager) weakManager = manager;
manager.authorizationAllowed = ^{
NSMutableDictionary *param = [NSMutableDictionary dictionary];
param[@"service_id"] = serviceId;
//7.3.0修改,@王成亮
[Phobos track:@"activity_promotion_seckill_notice" attributes:param];
[weakManager addEvent: title startDate: beginTime endDate: endTime serviceId: serviceId url: url];
};
if ([manager checkAuthorized]) {
if (notify) {
//添加提醒
NSMutableDictionary *param = [NSMutableDictionary dictionary];
param[@"service_id"] = serviceId;
[Phobos track:@"activity_promotion_seckill_notice" attributes:param];
[manager addEvent: title startDate: beginTime endDate: endTime serviceId: serviceId url: url];
} else {
//取消提醒
[manager removeEvent: serviceId];
}
}
}
/// 使用前端指定的颜色覆盖导航栏。默认只按照导航栏的高度进行覆盖。
/// 如果要自定义覆盖范围,可以完全重写这个方法
/// @param data 前端传过来的参数
- (void)showClientShadow:(NSDictionary *)data {
int isShow = [data[@"isShow"] intValue];
// color 的 value格式:“RGB,A”,并且每一位都是16进制
NSArray *colors = [data[@"color"] componentsSeparatedByString:@","];
if (isShow && colors.count == 2) {
self.navigationBar.isShowShadow = NO;
GMView *view = [[GMView alloc] initWithFrame:CGRectMake(0, 0, MAINSCREEN_WIDTH, OCNavigationBar.barHeight)];
[self.view addSubview:view];
view.tag = 2891;
CGFloat alpha = [colors.lastObject integerValue]/255.0;
view.backgroundColor = [UIColor colorWithHex:[colors.firstObject integerValue] alpha:alpha];
} else {
self.navigationBar.isShowShadow = YES;
[[self.view viewWithTag:2891] removeFromSuperview];
}
}
- (BOOL)jsIsLocationEnable {
BOOL isLocation = [GMLocationManager hasOpenLocationService];
NSString *javaScriptStr = [NSString stringWithFormat:@"window.gm.pack.run('isLocationEnableCallback',%d)",isLocation];
[self.webCompent.webView evaluateJavaScript:javaScriptStr completionHandler:nil];
return isLocation;
}
#pragma mark - 导航栏按键响应
- (void)backAction:(OCNavigationBarButton *)button {
// 目前只有签到页面和获取列表支持返回拦截,后续建议逐渐删除
if ([_jsGlobalObject[@"page_name"] isEqualToString:@"activity_list"]) {
[self.webCompent.webView evaluateJavaScript:@"window.gm.pack.run('activityListBack')" completionHandler:nil];
}
[self nativeBackToCallJS];
// 由前端控制当前页面的返回事件是否需要拦截
if (![_jsGlobalObject.allKeys containsObject:@"back_call"] ||
![_jsGlobalObject[@"back_call"] boolValue]) {
[super backAction:button];
}
}
- (void)rightButtonClicked:(OCNavigationBarButton *)button {
[super rightButtonClicked:button];
// 隐藏键盘,避免不必要的bug发生
[self.view endEditing:YES];
if (_isSign) {
return;
}
// 显示分享
if (_isShowShare) {
// self.shareView = nil 这句话不能删除。删除了会导致 shareView 的背景消失
self.shareView = nil;
[self.shareView showWithShareUrl:self.shareObject.url];
}
/*
统计预告分享pv uv(device)。另外数据端还可以利用这个做其它统计。in 7.0.5
*/
if ([self.pageName isNonEmpty] && _isShowShare) {
NSDictionary *dic = @{@"business_id": self.businessId,
@"page_name": self.pageName,
@"referrer": self.referer};
[Phobos track:@"on_click_common_webview_share" attributes:dic];
}
// 没有分享,只显示了一个JS_Button
if (!_isShowShare && _isJsRightButton) {
NSString *jumpURL = _jsGlobalObject[@"right_button"][@"url"];
NSString *jsFunction = _jsGlobalObject[@"right_button"][@"js_function"];
if ([jumpURL isNonEmpty]) {
[[GMRouter sharedInstance] pushScheme:jumpURL];
}
if ([jsFunction isNonEmpty]) {
[self.webCompent.webView evaluateJavaScript:jsFunction completionHandler:nil];
}
}
// 口红王子投票活动
if ([_jsGlobalObject[@"navigation"][@"right_action"] isNonEmpty]) {
NSString *rightAction = _jsGlobalObject[@"navigation"][@"right_action"];
[self.webCompent.webView evaluateJavaScript:rightAction completionHandler:nil];
}
}
- (void)nearRightButtonClicked:(OCNavigationBarButton *)button {
[super nearRightButtonClicked:button];
if (_isShowShare && _isJsRightButton) {
NSString *jumpURL = _jsGlobalObject[@"right_button"][@"url"];
NSString *jsFunction = _jsGlobalObject[@"right_button"][@"js_function"];
if ([jumpURL isNonEmpty]) {
[[GMRouter sharedInstance] pushScheme:jumpURL];
}
if ([jsFunction isNonEmpty]) {
[self.webCompent.webView evaluateJavaScript:jsFunction completionHandler:nil];
}
}
}
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (_isNavigationAlpha) {
// animationDistance 为0时表示header_height值在h5端还未确认
if (self.animationDistance > 0) {
[self animationBar:self.navigationBar withScrollView:scrollView];
} else {
CGFloat headerHeight = [_jsGlobalObject[@"header_height"] floatValue];
// 如果header_height不为0,表示图片大小已经确定,
if (headerHeight != 0) {
self.animationDistance = headerHeight - OCNavigationBar.barHeight;
}
}
CGFloat alpha = [self animationBar:self.navigationBar withScrollView:scrollView];
if (_isSign) {
// 签到 rightButton不隐藏ase
CGFloat offsetY = self.contentOffsetY > 0 ? self.contentOffsetY : scrollView.contentOffset.y;
self.navigationBar.rightButton.hidden = NO;
self.navigationBar.titleLabel.hidden = NO;
if (offsetY > [_jsGlobalObject[@"header_height"] floatValue] - OCNavigationBar.statusBarHeight) {
self.navigationBar.titleLabel.textColor = [UIColor colorWithWhite:0 alpha:alpha];
self.navigationBar.rightIconURL = _jsGlobalObject[@"navigation"][@"right_scrolled_button"];
self.navigationBar.leftIcon = @"back";
} else {
self.navigationBar.titleLabel.textColor = [UIColor whiteColor];
self.navigationBar.rightIconURL = _jsGlobalObject[@"navigation"][@"right_button"];
self.navigationBar.leftIcon = @"backWhite";
}
} else {
self.navigationBar.rightButton.hidden = !(alpha == 1);
}
}
}
- (void)showReport{
[self showComplete:@"举报成功,所长会尽快处理哒"];
}
/**
粘贴邀请好友口令到粘贴板
@param boardText 粘贴板文字
*/
- (void)jsClipboard:(NSString *)boardText {
UIPasteboard *board = [UIPasteboard generalPasteboard];
board.string = boardText;
[self toast:@"复制成功"];
}
//TODO: 代思考
#pragma mark - GMPhotoPickDismissDelegate
//- (void)dismissPhotoPick:(NSArray<GMEditPhotoInfo *> *)infos{
// if (infos.count == 0) {
// return ;
// }
// GMEditPhotoInfo *model = infos.firstObject;
// UIImage *image = model.finshedImage;
// NSString *remoteUrl = _isPrivatePhoto ? API_UPLOAD_IMAGE_SAFE : API_UPLOAD_IMAGE;
// WMImageUploadOperation *operation = [[WMImageUploadOperation alloc]initWithImage:image url:remoteUrl withCompressionQuality:0.75];
// [operation setImageUploadFinishBlock:^(NSDictionary *JSON) {
// NSString *publicUrl = @"";
// NSString *jsParam = @"";
//
// if (_isPrivatePhoto) {
// publicUrl = JSON[@"data"][@"public_url"];
// NSString *privateUrl = JSON[@"data"][@"private_url"];
// if ([publicUrl isNonEmpty] && [privateUrl isNonEmpty]) {
// NSDictionary *data = @{_requestCoder : @{@"private_url": privateUrl, @"public_url" : publicUrl}};
// NSData *jsParamData = [NSJSONSerialization dataWithJSONObject:data options:0 error:NULL];
// jsParam = [[NSString alloc] initWithData:jsParamData encoding:NSUTF8StringEncoding];
// }
// } else {
// publicUrl = JSON[@"data"][@"public_url"];
// NSDictionary *data = @{_requestCoder : @{@"public_url" : publicUrl}};
// NSData *jsParamData = [NSJSONSerialization dataWithJSONObject:data options:0 error:NULL];
// jsParam = [[NSString alloc] initWithData:jsParamData encoding:NSUTF8StringEncoding];
// }
//
// NSString *jsString = [NSString stringWithFormat:@"gm.util.setPageData('%@')",jsParam];
// [self.webCompent.webView evaluateJavaScript:jsString completionHandler:nil];
// }];
// [operation startUpload];
//}
//
//
//// 签到页弹窗提示后,点击不再提醒会调用
//- (void)jsSignNeverNotify {
// [self.navigationController popViewControllerAnimated:YES];
//}
- (int)jsIsUserLogin {
int isLogin = GMLoginManager.shareInstance.isVisitor ? 0 : 1;
NSString *javaScriptStr = [NSString stringWithFormat:@"window.gm.pack.run('isUserLoginCallback',%d)",isLogin];
[self.webCompent.webView evaluateJavaScript:javaScriptStr completionHandler:nil];
return isLogin;
}
// js 获取NativeData数据
- (NSString *)jsNativeDataLoaded {
NSString *trackerJson = [self nativeCommonParam];
if ([trackerJson isNonEmpty]) {
NSString *jsonStr = [NSString stringWithFormat:@"window.gm.pack.run('setNativeDataLoaded','%@')",trackerJson];
[self.webCompent.webView evaluateJavaScript:jsonStr completionHandler:nil];
return trackerJson;
}
return @"";
}
// 本地获取通用数据
- (NSString *)nativeCommonParam {
NSMutableDictionary *param = [NSMutableDictionary dictionaryWithDictionary:[NSDictionary trackerPageParam:self]];
[param setValue:SafeString(@(OCNavigationBar.barHeight)) forKey:@"title_bar_height"];
[param setValue:(self.referrerLink ? : @[]) forKey:@"referrer_link"];
// 仅当 cpc_referer 不为none时候传递此参数
if (self.cpc_referer != GMCpcNone) {
[param setValue:SafeString(@(self.is_cpc)) forKey:@"is_cpc"];
[param setValue:SafeString(@(self.cpc_referer)) forKey:@"cpc_referer"];
}
NSData *referrerData = [NSJSONSerialization dataWithJSONObject:param options:0 error:NULL];
NSString *trackerJson = [[NSString alloc] initWithData:referrerData encoding:NSUTF8StringEncoding];
if ([trackerJson isNonEmpty]) {
return trackerJson;
}
return @"";
}
- (NSString *)jsInflateUserInfo {
NSDictionary *userDic = @{@"user_id":@([GMLoginManager shareInstance].user.userId), @"user_name":SafeString([GMLoginManager shareInstance].user.nickName)};
NSData *userData = [NSJSONSerialization dataWithJSONObject:userDic options:0 error:NULL];
NSString *userParam = [[NSString alloc] initWithData:userData encoding:NSUTF8StringEncoding];
NSString *js = [NSString stringWithFormat:@"window.gm.pack.run('setInflateUserInfo',%@)",userParam];
[self.webCompent.webView evaluateJavaScript:js completionHandler:nil];
return userParam;
}
- (void)jsShowActionSheet:(NSString *)jsonString {
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding] options: NSJSONReadingAllowFragments error:nil];
if (jsonArray.count <= 0) {
return;
}
GMActionSheet *alertView = [[GMActionSheet alloc] init];
// 回复弹窗内容和回调方法
for (NSDictionary *dic in jsonArray) {
GMActionSheetItemType type;
if ([dic[@"title"] isEqualToString:@"取消"]) {
type = GMActionSheetItemTypeCancel;
[alertView addItemWithTitle:dic[@"title"] style:type color:UIColor.headlineText handle:nil];
} else {
__weak __typeof(self)weakSelf = self;
type = GMActionSheetItemTypeDefault;
[alertView addItemWithTitle:dic[@"title"] style:type color:UIColor.headlineText handle:^(NSInteger index) {
NSDictionary *className = jsonArray[index];
NSString *js = [NSString stringWithFormat:@"window.gm.pack.run('%@')", SafeString(className[@"callback"])];
[weakSelf.webCompent.webView evaluateJavaScript:js completionHandler:nil];
}];
}
}
[alertView show];
}
- (void)jsRightbuttonCallBack:(NSString *)json {
NSData *jsonData = [json dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
self.navigationBar.rightIconURL = dict[@"icon_url"];
}
- (int)jsNavigationbarHeight {
float barH = OCNavigationBar.barHeight;
NSString *javaScriptStr = [NSString stringWithFormat:@"window.gm.pack.run('navigationbarHeightCallback',%f)",barH];
[self.webCompent.webView evaluateJavaScript:javaScriptStr completionHandler:nil];
return OCNavigationBar.barHeight;
}
- (void)jsCheckAuthority:(NSString *)jsonString {
[AppDelegate.shareInstance userIsAllowPush:^(BOOL status) {
if (!status) {
_isSettingCallback = YES;
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
GMCommonAlertView *alertView = [[GMCommonAlertView alloc] init];
alertView.titleLabel.text = dict[@"title"];
alertView.subLabel.text = dict[@"tip"];
[alertView.button1 setTitle:dict[@"openName"] forState:UIControlStateNormal];
[alertView.button2 setTitle:dict[@"cancelName"] forState:UIControlStateNormal];
alertView.button3.hidden = YES;
self.settingType = [dict[@"type"] integerValue];
alertView.delegate = self;
[alertView show];
} else {
[self excuteSettingCallback:YES];
}
}];
}
//TODO: 待解决
//- (void)didClickCommonAlertWithButtonIndex:(NSInteger)buttonIndex alertView:(GMCommonAlertView *)alertView {
// [alertView dismiss];
// if (buttonIndex == 1) {
// //打开
// [self goToAppSystemSettings];
// self.goToAppSettingsPage = YES;
// } else if (buttonIndex == 2) {
// [self excuteSettingCallback:NO];
// }
//}
- (void)excuteSettingCallback:(BOOL)setting {
NSString *javaScriptStr = [NSString stringWithFormat:@"window.gm.pack.run('settingCallback',%d)",setting];
[self.webCompent.webView evaluateJavaScript:javaScriptStr completionHandler:nil];
}
#pragma mark - Native Call JS
/// Native 告知 H5页面展现
- (void)nativeAppearToCallJS {
[self.webCompent.webView evaluateJavaScript:@"window.gm&&window.gm.pack&&window.gm.pack.run('appear')" completionHandler:nil];
}
/// Native 告知 H5页面不可见
- (void)nativeDisAppearToCallJS {
[self.webCompent.webView evaluateJavaScript:@"window.gm&&window.gm.pack&&window.gm.pack.run('disappear')" completionHandler:nil];
}
/// Native 告知 H5返回执行
- (void)nativeBackToCallJS {
[self.webCompent.webView evaluateJavaScript:@"window.gm.pack.run('backAction')" completionHandler:nil];
}
/// Native 告知 H5取消登录
- (void)nativeLoginCancelToCallJS {
[self.webCompent.webView evaluateJavaScript:@"window.gm.pack.run('loginCancel')" completionHandler:nil];
}
/// Native 告知 H5进入后台
- (void)nativeEnterBackgroundToCallJS {
[self.webCompent.webView evaluateJavaScript:@"window.gm.pack.run('enterBackground')" completionHandler:nil];
}
/// Native 告知 H5进入前台
- (void)nativeEnterForgroundToCallJS {
[self.webCompent.webView evaluateJavaScript:@"window.gm.pack.run('enterForground')" completionHandler:nil];
}
#pragma mark - 埋点
/*** type由h5负责,所有h5埋点的方法都走这里 */
- (void)jsTrackEvent:(NSString *)JSONString {
@try {
NSData *data = [JSONString dataUsingEncoding:NSUnicodeStringEncoding];
NSMutableDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
id pa = dict[@"params"];
BOOL sendNow = [dict[@"nowSend"] boolValue];
NSDictionary *json;
if (pa != nil) {
if ([pa isKindOfClass:[NSString class]]) {
NSError *jsonError;
NSData *objectData = [pa dataUsingEncoding:NSUTF8StringEncoding];
json = [NSJSONSerialization JSONObjectWithData:objectData
options:NSJSONReadingMutableContainers
error:&jsonError];
[Phobos track:dict[@"type"] attributes:json sendNow:sendNow];
}else{
[Phobos track:dict[@"type"] attributes:dict[@"params"] sendNow:sendNow];
}
} else {
[Phobos track:dict[@"type"] attributes:@{} sendNow:sendNow];
}
}
@catch (NSException *exception) {
debugLog(@"exception:%@",exception);
}
}
/*** 精准曝光 */
- (void)jsHybridExposure:(NSString *)JSONString {
@try {
NSData *data = [JSONString dataUsingEncoding:NSUnicodeStringEncoding];
NSMutableDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
if (dict) {
[Phobos track:@"page_precise_exposure" attributes:dict sendNow:YES currentAPI:GMExactExposureApi];
}
}
@catch (NSException *exception) {
debugLog(@"exception:%@",exception);
}
}
#pragma mark - notification
- (void)addActiveObserver {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didBecomeActive)
name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(willResignActive)
name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(loginCancelNotification)
name:LOGIN_CANCEL_NOTIFICATION object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(enterBackground)
name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(enterForground)
name:UIApplicationWillEnterForegroundNotification object:nil];
}
- (void)enterBackground {
[self nativeEnterBackgroundToCallJS];
}
- (void)enterForground {
[self nativeEnterForgroundToCallJS];
}
- (void)willResignActive {
// 活动页面
if ([_jsGlobalObject[@"page_name"] isEqualToString:@"activity_list"]) {
[self nativeDisAppearToCallJS];
}
}
- (void)didBecomeActive {
if ([_jsGlobalObject[@"page_name"] isEqualToString:@"activity_list"]) {
[self nativeAppearToCallJS];
}
// 前往设置页面后 回到当前页面需要告知前端状态,前端会直接弹出“开抢提醒”弹框
if (self.goToAppSettingsPage) {
[AppDelegate.shareInstance userIsAllowPush:^(BOOL status) {
[self excuteSettingCallback:status];
// 返回app的时候把数据清空了,所以延迟3秒执行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 获取通知权限浮层页授权按钮点击(需要获取授权状态)
[Phobos track:@"authority_page_click" attributes:@{@"user_id":@([GMLoginManager shareInstance].user.userId), @"authority_type":@(status)}];
});
}];
}
// 由于秒杀专场使用了common_webivew协议,所以这段逻辑不得不放到这个controller里,并且添加相关页面的判断
// 秒杀专场的url activity/promotion/1024/seckill
// 美购专题的url special_promotion
if ([_jsGlobalObject[@"is_seckill"] boolValue] && [GMLocationManager hasOpenLocationService] &&
[GMLocationManager shareInstance].statusWhenAppBackground != [CLLocationManager authorizationStatus]) {
/*
当系统地理位置权限改变后再回到app时,需要刷新webview,也就是说要重新确认 is_location_enable 参数的状态
由于先前使用的是query的方式来取得该参数,导致在webView.refresh时,该参数状态还是原来的状态,并没有改变
所以采取了下面强制webview重新loadRequest
由于是又加载了一个页面,在后退时webView是内部后退,而不是controller后退,所以又得重写 backAction 方法
如果h5方便的时候,将 is_location_enable 改为js主动获取,而不是使用query参数,这样更灵活。
*/
[self webViewLoadRequest];
}
}
// 用户取消登录通知
- (void)loginCancelNotification {
[self nativeLoginCancelToCallJS];
}
#pragma mark - lazy loading
- (GMWebViewComponent *)webCompent {
if (!_webCompent) {
_webCompent = [GMWebViewComponent new];
_webCompent.delegate = self;
_webCompent.clientH5Object.delegate = self;
}
if (!_webCompent.superview) {
[self.view addSubview:_webCompent];
}
return _webCompent;
}
- (GMShareView *)shareView{
if (!_shareView) {
_shareView = [[GMShareView alloc] init];
_shareView.delegate = self;
}
return _shareView;
}
- (GMDiaryShareView *)diaryShareView {
if (!_diaryShareView) {
_diaryShareView = [[GMDiaryShareView alloc] init];
_diaryShareView.delegate = self;
}
return _diaryShareView;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
// 在某些情况下,如果controller先dealloc了,会导致webView找不到delegate而crash。例如修复jspatch与webview冲突时就会遇到。
// 复现步骤:先注释以下代码,再push到一个webController,加载时立即后退,等待,然后crash,提示 “webView:identifierForInitialRequest:fromDataSource”
_webCompent.delegate = nil;
[_webCompent.webView stopLoading];
}
@end
//
// GMClientH5Object.h
// Gengmei
//
// Created by wangyang on 7/25/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>
// 设置打开的权限类型
typedef NS_ENUM(NSInteger, GMSettingType) {
// 推送
GMSettingTypePush,
// 位置
GMSettingTypeLocation
};
/**
* @brief 在这里声明js对象所有绑定的方法(名字要和js注册的方法保持一致),命名规范以JS端为准
*/
@protocol GMClientH5Bridge <JSExport>
#pragma mark - 下面这些放到Base里
/*** @brief 返回到上级页面*/
- (void)jsPop:(BOOL)animated;
/*** @brief 返回域名, 这个不需要代理在controller实现*/
- (NSString *)domain;
/*** @brief 弹出loading框*/
- (void)showLoading;
/*** @brief 隐藏loading*/
- (void)hideLoading;
/*** @brief Alert弹窗(只有一个确认按钮)*/
- (void)showAlert:(NSString *)JSONString;
/*** @brief Confirm弹窗(确认和取消按钮*/
- (void)showConfirm:(NSString *)JSONString;
/*** @brief toast弹窗*/
- (void)showToast:(NSString *)JSONString;
/*** @brief 埋点功能 ,js掉native方法方式埋点 */
- (void)trackEvent:(NSString *)JSONString;
/*** @brief 精准曝光 */
- (void)hybridExposure:(NSString *)JSONString;
/*** @brief 回放 */
- (void)playVideo:(NSString *)JSONString;
/*** @brief 获取通讯录 */
- (void)getAddressBook;
/*** 选择一个联系人 */
- (void)chooseOneContactPerson:(NSString *)key;;
- (void)logout;
/*** @brief 打开外部浏览器*/
- (void)openBrowser:(NSString *)url;
/**
* @author wangyang, 16-03-11 15:03:43
*
* @brief 如果目前没有地理位置权限,h5调用该方法跳转到系统的定位功能
* @since 5.9.2
*/
- (void)jumpToLocationSettings;
/**
* @author wangyang, 16-03-11 15:03:43
*
* @brief 如果目前没有地理位置权限,h5调用该方法显示弹窗,要求获取权限
* @since 5.9.2
*/
- (void)locationShowAlertIfNotAllowed;
/*** @brief 显示分享美券页面
邀请好友, 所长发券页在使用。使用了globalObjectLoaded
*/
- (void)jsObjShowShareView:(NSString *)JSONString;
/*** @brief 分享日记
连续签到,补签
*/
- (void)jsObjShowDiaryShareView:(NSString *)JSONString;
/*** @brief 显示小分享(仅微信好友/微信朋友圈)页面
在老版本的支付完成页使用,先弹出一个本地的分享视图,再分享。从6.2.0开始已经不再使用
*/
- (void)showWXShareView:(NSString *)JSONString;
//抛出两个方法让服务器存储使用
- (void)setLocalStorage:(NSString *)key WithBody:(NSString *)value;
- (NSString *)getLocalStorage:(NSString *)key;
//秒杀页面是否展示定位
- (BOOL)isLocationEnable;
/**
* @author wangyang, 16-01-22 18:01:16
*
* @brief H5 主动调用本地分享方法,直接分享到某个平台。在订单详情页发红包弹出的webView里被调用
* @param data JSON
* @param type QZone/QQ/Wechat/WechatMoments/SinaWeibo
* @since 5.9.0
*/
- (void)share:(NSString *)shareDataString withType:(NSString *)type;
/**
* @author wangjun, 16-07-04 12:07:24
*
* 秒杀页面的添加到系统日历的事件的方法
* @param jsonString json字符串
* @since 6.1.0
*/
- (void)remindEvent: (NSString *)jsonString;
///保险回调
- (void)insurancePurchase:(BOOL)hasBought;
///打电话
- (void)callPhone:(NSString *)phone;
///发短信
- (void)sendMessage:(NSString *)phone withBody:(NSString *)body;
//日记本详情打开通知Alert
- (void)diaryDetailShowNotificationAlert;
/**
用来动画导航栏的。参考日记帖详情页PostDetailViewController
@param height 可动画的高度
*/
- (void)setHeaderHeight:(NSInteger)height;
// 从h5登录,保存session及用户信息
- (void)syncSSOInfo:(NSString *)info;
//场景化弹窗
- (void)showTaskAlert:(NSString *)extra;
// 新用户领券是否成功
- (void)newbieCouponGot:(NSInteger)flag;
/**
邀请好友粘贴口令
@param boardText 口令值
*/
- (void)clipboard:(NSString *)boardText;
/**
回复框弹窗
@param jsonString 弹窗内容和回调方法
*/
- (void)showActionSheet:(NSString *)jsonString;
/**
右上角关注按钮
@param json icon_url:关注/未关注图片
*/
- (void)rightbuttonCallBack:(NSString *)json;
/**
机构主页
@param jsonString pageData
*/
- (void)globalDataLoaded:(NSString *)jsonString;
/**
是否登录:1登录 0未登录
*/
- (int)isUserLogin;
/**
获取用户信息
*/
- (NSString *)inflateUserInfo;
/**
机构详情:yes:导航栏显示,no:导航栏隐藏
*/
- (void)controlTitleBarVisible:(NSString *)jsonString;
/**
回复详情:底栏数据
*/
- (void)answerData:(NSString *)jsonString;
/**
问题详情:底栏数据
*/
- (void)questionData:(NSString *)jsonString;
/**
导航栏高度
*/
- (int)navigationbarHeight;
/**
签到提醒开关
*/
- (void)checkAuthority:(NSString *)jsonString;
/**
网络状态 2: 其他 1:wifi 0:无网络
*/
- (NSInteger)checkNetworkState;
- (NSString *)nativeDataLoaded;
/**
签到页弹窗点击不再提醒
*/
- (void)signNeverNotify;
/**
展示空的页面
*/
-(void)showNativeEmptyView;
/**
调起第三方APP
*/
- (void)skipToThirdApp:(NSString *)jsonString;
/**
面孔起源结果页跳转列表页
*/
- (void)jumpToResearchPage:(NSString *)url;
/**
面诊记录报告页面保存图片
*/
- (void)saveImage:(NSString *)url;
/**
调起评论列表
*/
- (void)showCommentList:(NSString *)JSONString;
@end
/*** @brief 在这里声明 js 要调用的方法*/
@protocol GMClientH5BridgeDelegate <NSObject>
@optional
/*** @brief 显示分享美券页面*/
- (void)jsObjShowShareViewWithJSONString:(NSString *)JSONString;
/*** @brief 连续签到,补签分享日记*/
- (void)jsObjShowDiaryShareViewWithJSONString:(NSString *)JSONString;
/*** @brief 显示小分享(仅微信好友/微信朋友圈)页面*/
- (void)jsShowWXShareViewWithJSONString:(NSString *)JSONString;
/*** @brief 返回到上级页面*/
- (void)jsPopViewControllerAnimated:(BOOL)animated;
/*** @brief 弹出loading框*/
- (void)jsShowLoading;
- (void)jsShowNativeEmptyView;
/*** @brief 隐藏loading*/
- (void)jsHideLoading;
/*** @brief Alert弹窗(只有一个确认按钮)*/
- (void)jsShowAlertViewWithJSONString:(NSString *)JSONString;
/*** @brief Confirm弹窗(确认和取消按钮*/
- (void)jsShowConfirmViewWithJSONString:(NSString *)JSONString;
/*** @brief toast弹窗*/
- (void)jsShowToastWithJSONString:(NSString *)JSONString;
/*** @brief 供h5吊起选图上传的方法 */
- (void)jsOpenAlbum:(NSString *)requestCode is_private:(BOOL)isPrivate;
/*** @brief 获取通讯录 */
- (void)jsGetAddressBook;
- (void)jsChooseOneContactPerson:(NSString *)key;
/**
* @author wangyang, 15-10-08 15:10:56
*
* @brief 见 applyForStage 方法
* @since 5.2.0
*/
- (void)jsApplyForStage:(NSString *)url;
/*** @brief 埋点功能 ,js掉native方法方式埋点 */
- (void)jsTrackEvent:(NSString *)JSONString;
/*** @brief 精准曝光 */
- (void)jsHybridExposure:(NSString *)JSONString;
/*** @brief 回放 */
- (void)jsPlayVideo:(NSString *)JSONString;
/**
* @author wangyang, 16-12-31 16:12:05
*
* @brief h5 调用注销方法
* @since 5.8.0
*/
- (void)jsLogout;
/**
* @author wangyang, 16-01-22 18:01:03
*
* @brief 见 share:withType:
* @since 5.9.0
*/
- (void)jsShare:(NSString *)shareDataString withType:(NSString *)type;
//以便H5存储使用
- (void)jsSetLocalStorage:(NSString *)key withStorage:(NSString *)value;
- (NSString *)jsGetLocalStorage:(NSString *)key;
/*** @brief 打开外部浏览器*/
- (void)jsOpenBrowser:(NSString *)url;
/**
* @author wangyang, 16-03-11 15:03:43
*
* @brief 如果目前没有地理位置权限,h5调用该方法跳转到系统的定位功能
* @since 5.9.2
*/
- (void)jsJumpToLocationSettings;
//秒杀页面是否需要展示打开定位
- (BOOL)jsIsLocationEnable;
/**
* @author wangyang, 16-03-11 15:03:43
*
* @brief 如果目前没有地理位置权限,h5调用该方法显示弹窗,要求获取权限
* @since 5.9.2
*/
- (void)jsLocationShowAlertIfNotAllowed;
/**
* @author wangjun, 16-03-17 16:03:12
*
* @brief 赚美分页面的动画效果
*
* @param dict H5调用所传的参数字典
*
* @since 5.9.2
*/
- (void)jsShowBong:(NSString *)jsonString;
/**
* @author wangjun, 16-07-04 12:07:08
*
* 秒杀页面的添加到系统日历的事件的方法
* @param jsonString H5穿来的json字符串
* @since 6.1.0
*/
- (void)jsRemindEvent:(NSString *)jsonString;
/**
* 保险状态返回
* @paramhas_bought: true(确定购买) / false(取消购买)
* @since 6.6.0
*/
- (void)jsInsurancePurchase:(NSDictionary *)dict;
///打电话
- (void)jsCallPhone:(NSString *)phone;
///发短信
- (void)jsSendMessage:(NSString *)phone withBody:(NSString *)body;
- (void)jsSetHeaderHeight:(NSInteger)height;
// 打开通知方法
- (void)jsDiaryDetailShowNotificationAlert;
// 前端登录信息同步到客户端
- (void)jsSyncSSOInfo:(NSString *)info;
//场景化弹窗由JS调用
- (void)jsShowTaskAlert:(NSString *)extra;
// 新用户领券是否成功
- (void)jsNewbieCouponGot:(NSInteger)flag;
/**
邀请好友粘贴口令
@param boardText 口令值
*/
- (void)jsClipboard:(NSString *)boardText;
/**
回复弹窗
@param jsonString 弹窗名称和回调方法
*/
- (void)jsShowActionSheet:(NSString *)jsonString;
/**
右上角关注按钮
@param json icon_url:关注/未关注图片
*/
- (void)jsRightbuttonCallBack:(NSString *)json;
/**
机构主页
@param jsonString pageData
*/
- (void)jsGlobalDataLoaded:(NSString *)jsonString;
/**
是否登录
*/
- (int)jsIsUserLogin;
/**
获取用户信息
*/
- (NSString *)jsInflateUserInfo;
- (NSString *)jsNativeDataLoaded;
/**
机构详情:yes:导航栏显示,no:导航栏隐藏
*/
- (void)jsControlTitleBarVisible:(NSString *)jsonString;
/**
回复详情:底栏数据
*/
- (void)jsAnswerData:(NSString *)jsonString;
/**
问题详情:底栏数据
*/
- (void)jsQuestionData:(NSString *)jsonString;
/**
导航栏高度
*/
- (int)jsNavigationbarHeight;
/**
签到提醒开关
*/
- (void)jsCheckAuthority:(NSString *)jsonString;
/**
网络状态 2: 其他 1:wifi 0:无网络
*/
- (NSInteger)jsCheckNetworkState;
/**
签到页弹窗点击不再提醒
*/
- (void)jsSignNeverNotify;
/**
调起第三方APP
*/
- (void)jsSkipToThirdApp:(NSString *)jsonString;
/// js 直接掉起指定平台分享
/// @param jsonString 分享数据
- (void)jsSharewithType:(NSDictionary *)data;
/// 更新页面上导航数据
/// @param JSONString @param JSONString {"title":"","business_id":""}
- (void)jsScrollSetHeader:(NSDictionary *)data;
/// 弹出l评论列表+评论输入
/// @param data @param JSONString {"title":"","business_id":""}
- (void)jsShowCommentList:(NSDictionary *)data;
/// 弹出回答输入框
/// @param data @param JSONString
- (void)jsShowAnswerInput:(NSDictionary *)data;
/**
面孔起源结果页跳转列表页
*/
- (void)jsJumpToResearchPage:(NSString *)url;
/**
面诊记录报告页面保存图片
*/
- (void)jsSaveImage:(NSString *)url;
/// 查看今日运势( isSaveSocial: 是否保存到社区)
/// @param data @param JSONString {"isSaveSocial":"1"}
- (void)jsShowToDayLuck:(NSDictionary *)data;
@end
@interface GMClientH5Object : NSObject <GMClientH5Bridge>
@property (nonatomic, weak) id<GMClientH5BridgeDelegate> delegate;
@end
//
// GMClientH5Object.m
// Gengmei
//
// Created by wangyang on 7/25/15.
// Copyright (c) 2015 Wanmeichuangyi. All rights reserved.
//
#import "GMClientH5Object.h"
#import <GMFoundation/GMFoundation-umbrella.h>
//#import "GMLaunchManager.h"
#import "GMBaseWebViewController.h"
/**
* @author licong, 15-12-25 15:12:44
*
* JSCore引擎调用OC做UI渲染操作,必须保证是在主线程执行,所以都加了 dispatch_async 以保证主线程工作
*
*/
@implementation GMClientH5Object
- (void)jsObjShowShareView:(NSString *)JSONstring{
if ([self.delegate respondsToSelector:@selector(jsObjShowShareViewWithJSONString:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsObjShowShareViewWithJSONString:JSONstring];
});
}
}
- (void)jsObjShowDiaryShareView:(NSString *)JSONString {
if ([self.delegate respondsToSelector:@selector(jsObjShowDiaryShareViewWithJSONString:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsObjShowDiaryShareViewWithJSONString:JSONString];
});
}
}
- (void)showWXShareView:(NSString *)JSONstring{
if ([self.delegate respondsToSelector:@selector(jsShowWXShareViewWithJSONString:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsShowWXShareViewWithJSONString:JSONstring];
});
}
}
- (void)jsPop:(BOOL)animated{
if ([self.delegate respondsToSelector:@selector(jsPopViewControllerAnimated:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsPopViewControllerAnimated:animated];
});
}
}
//TODO: 待修改
- (NSString *)domain{
return @"";
// return APIHOST;
}
- (void)showLoading{
if ([self.delegate respondsToSelector:@selector(jsShowLoading)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsShowLoading];
});
}
}
- (void)hideLoading{
if ([self.delegate respondsToSelector:@selector(jsHideLoading)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsHideLoading];
});
}
}
- (void)showAlert:(NSString *)JSONString{
if ([self.delegate respondsToSelector:@selector(jsShowAlertViewWithJSONString:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsShowAlertViewWithJSONString:JSONString];
});
}
}
- (void)showConfirm:(NSString *)JSONString{
if ([self.delegate respondsToSelector:@selector(jsShowConfirmViewWithJSONString:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsShowConfirmViewWithJSONString:JSONString];
});
}
}
- (void)showToast:(NSString *)JSONString{
if ([self.delegate respondsToSelector:@selector(jsShowToastWithJSONString:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsShowToastWithJSONString:JSONString];
});
}
}
- (void)trackEvent:(NSString *)JSONString {
dispatch_async(dispatch_get_main_queue(), ^{
if ([self.delegate respondsToSelector:@selector(jsTrackEvent:)]) {
[self.delegate jsTrackEvent:JSONString];
}
});
}
- (void)playVideo:(NSString *)JSONString {
if ([self.delegate respondsToSelector:@selector(jsPlayVideo:)]) {
[self.delegate jsPlayVideo:JSONString];
}
}
- (void)getAddressBook {
if ([self.delegate respondsToSelector:@selector(jsGetAddressBook)]) {
[self.delegate jsGetAddressBook];
}
}
- (BOOL)isLocationEnable {
if ([self.delegate respondsToSelector:@selector(jsIsLocationEnable)]) {
return [self.delegate jsIsLocationEnable];
} else {
return NO;
}
}
- (void)chooseOneContactPerson:(NSString *)key {
if ([self.delegate respondsToSelector:@selector(jsChooseOneContactPerson:)]) {
[self.delegate jsChooseOneContactPerson:key];
}
}
- (void)logout {
if ([self.delegate respondsToSelector:@selector(jsLogout)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsLogout];
});
}
}
- (void)share:(NSString *)shareDataString withType:(NSString *)type{
if ([self.delegate respondsToSelector:@selector(jsShare:withType:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsShare:shareDataString withType:type];
});
}
}
- (void)openBrowser:(NSString *)url{
if ([self.delegate respondsToSelector:@selector(jsOpenBrowser:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsOpenBrowser:url];
});
}
}
- (void)jumpToLocationSettings {
if ([self.delegate respondsToSelector:@selector(jsJumpToLocationSettings)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsJumpToLocationSettings];
});
}
}
- (void)locationShowAlertIfNotAllowed {
if ([self.delegate respondsToSelector:@selector(jsLocationShowAlertIfNotAllowed)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsLocationShowAlertIfNotAllowed];
});
}
}
- (void)diaryDetailShowNotificationAlert {
if ([self.delegate respondsToSelector:@selector(jsDiaryDetailShowNotificationAlert)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsDiaryDetailShowNotificationAlert];
});
}
}
- (void)remindEvent:(NSString *)jsonString {
if ([self.delegate respondsToSelector:@selector(jsRemindEvent:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsRemindEvent:jsonString];
});
}
}
- (void)insurancePurchase:(BOOL)hasBought {
if ([self.delegate respondsToSelector:@selector(jsInsurancePurchase:)]) {
NSDictionary *dict = @{@"has_bought": @(hasBought)};
[self.delegate jsInsurancePurchase:dict];
}
}
- (void)callPhone:(NSString *)phone {
if ([self.delegate respondsToSelector:@selector(jsCallPhone:)]) {
[self.delegate jsCallPhone:phone];
}
}
- (void)sendMessage:(NSString *)phone withBody:(NSString *)body {
if ([self.delegate respondsToSelector: @selector(jsSendMessage:withBody:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsSendMessage:phone withBody:body];
});
}
}
- (void)setHeaderHeight:(NSInteger)height {
if ([self.delegate respondsToSelector: @selector(jsSetHeaderHeight:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsSetHeaderHeight:height];
});
}
}
- (void)setLocalStorage:(NSString *)key WithBody:(NSString *)value {
if ([self.delegate respondsToSelector: @selector(jsSetLocalStorage:withStorage:)]) {
[self.delegate jsSetLocalStorage:key withStorage:value];
}
}
- (NSString *)getLocalStorage:(NSString *)key {
if ([self.delegate respondsToSelector: @selector(jsGetLocalStorage:)]) {
return [self.delegate jsGetLocalStorage:key];
} else {
return @"";
}
}
- (void)syncSSOInfo:(NSString *)info {
if ([self.delegate respondsToSelector:@selector(jsSyncSSOInfo:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsSyncSSOInfo:info];
});
}
}
//场景化弹窗
- (void)showTaskAlert:(NSString *)extra {
if ([self.delegate respondsToSelector:@selector(jsShowTaskAlert:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsShowTaskAlert:extra];
});
}
}
- (void)newbieCouponGot:(NSInteger)flag {
if ([self.delegate respondsToSelector:@selector(jsNewbieCouponGot:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsNewbieCouponGot:flag];
});
}
}
- (void)clipboard:(NSString *)boardText {
if ([self.delegate respondsToSelector:@selector(jsClipboard:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsClipboard:boardText];
});
}
}
- (void)showActionSheet:(NSString *)jsonString {
if ([self.delegate respondsToSelector:@selector(jsShowActionSheet:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsShowActionSheet:jsonString];
});
}
}
- (void)showNativeEmptyView {
if ([self.delegate respondsToSelector:@selector(jsShowNativeEmptyView)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsShowNativeEmptyView];
});
}
}
- (void)rightbuttonCallBack:(NSString *)json {
if ([self.delegate respondsToSelector:@selector(jsRightbuttonCallBack:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsRightbuttonCallBack:json];
});
}
}
- (void)globalDataLoaded:(NSString *)jsonString {
if ([self.delegate respondsToSelector:@selector(jsGlobalDataLoaded:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsGlobalDataLoaded:jsonString];
});
}
}
- (int)isUserLogin {
if ([self.delegate respondsToSelector: @selector(jsIsUserLogin)]) {
return [self.delegate jsIsUserLogin];
} else {
return 0;
}
}
- (NSString *)inflateUserInfo {
if ([self.delegate respondsToSelector: @selector(jsInflateUserInfo)]) {
return [self.delegate jsInflateUserInfo];
} else {
return @"";
}
}
- (void)controlTitleBarVisible:(NSString *)jsonString {
if ([self.delegate respondsToSelector:@selector(jsControlTitleBarVisible:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsControlTitleBarVisible:jsonString];
});
}
}
- (void)answerData:(NSString *)jsonString {
if ([self.delegate respondsToSelector:@selector(jsAnswerData:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsAnswerData:jsonString];
});
}
}
- (void)questionData:(NSString *)jsonString {
if ([self.delegate respondsToSelector:@selector(jsQuestionData:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsQuestionData:jsonString];
});
}
}
- (int)navigationbarHeight {
if ([self.delegate respondsToSelector:@selector(jsNavigationbarHeight)]) {
return [self.delegate jsNavigationbarHeight];
} else {
return 0;
}
}
- (void)checkAuthority:(NSString *)jsonString {
if ([self.delegate respondsToSelector:@selector(jsCheckAuthority:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsCheckAuthority:jsonString];
});
}
}
/**
网络状态 2: 其他 1:wifi 0:无网络
*/
- (NSInteger)checkNetworkState {
if ([self.delegate respondsToSelector:@selector(jsCheckNetworkState)]) {
return [self.delegate jsCheckNetworkState];
} else {
return 0;
}
}
//#warning TODO
- (NSString *)nativeDataLoaded {
if ([self.delegate isKindOfClass:[GMBaseWebViewController class]]) {
//如果是GMBaseWebViewController 会与v7.23.0因此这样写 webCompent.webView evaluateJavaScript
NSString *str;
if ([self.delegate respondsToSelector:@selector(jsNativeDataLoaded)]) {
str = [self.delegate jsNativeDataLoaded];
} else {
str = @"";
}
return str;
} else {
__block NSString *str;
dispatch_semaphore_t sem = dispatch_semaphore_create(1);
dispatch_async(dispatch_get_main_queue(), ^{
if ([self.delegate respondsToSelector:@selector(jsNativeDataLoaded)]) {
str = [self.delegate jsNativeDataLoaded];
} else {
str = @"";
}
dispatch_semaphore_signal(sem);
});
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
return str;
}
}
- (void)signNeverNotify {
if ([self.delegate respondsToSelector:@selector(jsSignNeverNotify)]) {
return [self.delegate jsSignNeverNotify];
}
}
- (void)skipToThirdApp:(NSString *)jsonString {
if ([self.delegate respondsToSelector:@selector(jsSkipToThirdApp:)]) {
[self.delegate jsSkipToThirdApp:jsonString];
}
}
/// 调起指定分享平台
/// @param JSONString {"share_data":{},"type":"Wechat"}
- (void)sharewithType:(NSString *)JSONString {
if ([self.delegate respondsToSelector:@selector(jsSharewithType:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsSharewithType:[NSDictionary dictionaryWithJsonString:JSONString]];
});
}
}
/// 更新页面上导航数据
/// @param JSONString @param JSONString {"title":"","business_id":""}
- (void)scrollSetHeader:(NSString *)JSONString {
if ([self.delegate respondsToSelector:@selector(jsScrollSetHeader:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsScrollSetHeader:[NSDictionary dictionaryWithJsonString:JSONString]];
});
}
}
/// 弹出评论列表+评论回复页面
/// @param JSONString JSONString
- (void)showCommentList:(NSString *)JSONString {
if ([self.delegate respondsToSelector:@selector(jsShowCommentList:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsShowCommentList:[NSDictionary dictionaryWithJsonString:JSONString]];
});
}
}
/// 弹出回答输入框
/// @param data @param JSONString
- (void)showAnswerInput:(NSString *)JSONString {
if ([self.delegate respondsToSelector:@selector(jsShowAnswerInput:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsShowAnswerInput:[NSDictionary dictionaryWithJsonString:JSONString]];
});
}
}
/// 跳转下一个启动项页面
//TODO: - 待修改
- (void)jumpNextLaunchPage {
dispatch_async(dispatch_get_main_queue(), ^{
// [[GMLaunchManager shareManager] jumpToNextLaunchPage];
});
}
- (void)jumpToResearchPage:(NSString *)url {
if ([self.delegate respondsToSelector:@selector(jsJumpToResearchPage:)]) {
[self.delegate jsJumpToResearchPage:url];
}
}
- (void)hybridExposure:(NSString *)JSONString {
if ([self.delegate respondsToSelector:@selector(jsHybridExposure:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsHybridExposure:JSONString];
});
}
}
- (void)saveImage:(NSString *)JSONString {
if ([self.delegate respondsToSelector:@selector(jsSaveImage:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsSaveImage:JSONString];
});
}
}
/// 查看今日运势( isSaveSocial: 是否保存到社区)
/// @param data @param JSONString {"isSaveSocial":"1"}
- (void)showToDayLuck:(NSString *)JSONString {
if ([self.delegate respondsToSelector:@selector(jsShowToDayLuck:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate jsShowToDayLuck:[NSDictionary dictionaryWithJsonString:JSONString]];
});
}
}
@end
//
// GMWebEngine.swift
// GMDoctor
//
// Created by Thierry on 16/6/21.
// Copyright © 2016年 Gengmei. All rights reserved.
//
import Foundation
import WebKit
//import GMUtil
//import EVReflection
class GMWebEngine {
var cookies: [String] = []
weak var webView: WKWebView?
/// WKScriptMessageHandler
/// 添加一个名称,就可以让JS通过这个名称发送消息:valueName自定义名字
/// window.webkit.messageHandlers.valueName.postMessage({body: 'xxx'})
public var scriptMessageHandlerArray: [String] = [String]()
/// 默认最小字体字体
public var minFontSize: CGFloat = 0
/// 显示滚动条
public var isShowScrollIndicator: Bool = true
/// 开启手势交互
public var isAllowsBackForwardGestures: Bool = true
/// 是否允许加载javaScript
public var isjavaScriptEnabled: Bool = true
/// 是否允许JS自动打开窗口的,必须通过用户交互才能打开
public var isAutomaticallyJavaScript: Bool = true
/// 是否影藏进度条
public var isProgressHidden: Bool = false
/// 进度条高度
public var progressHeight: CGFloat = 1
/// 默认颜色
public var progressTrackTintColor: UIColor = UIColor.mainVisual
/// 加载颜色
public var progressTintColor: UIColor = UIColor.mainVisual
init() {
syncCookies()
}
/**
同步Cookie
WKWebView不再和NSURLSession共享Cookie,所以需要手动同步
*/
func syncCookies() {
cookies.removeAll()
for cookie in HTTPCookieStorage.shared.cookies(for: URL(string: GMServerDomains.apiHost)!)! {
let value = "\(cookie.name)=\(cookie.value)"
cookies.append(value)
}
}
/**
构造Ajax Cookie的Script
in 2.3.0
- returns script
*/
func ajaxCookie() -> String {
var source = ""
for cookie in HTTPCookieStorage.shared.cookies(for: URL(string: GMServerDomains.apiHost)!)! {
var string = "\(cookie.name)=\(cookie.value);domain=\(cookie.domain);path=\(cookie.path); expires=\(String(describing: cookie.expiresDate))"
if cookie.isSecure {
string = "\(string);secure=true"
}
source.append("document.cookie='\(string)';")
}
return source
}
func webCookie() -> String {
return cookies.joined(separator: ";")
// let cookieStr = cookies.joined(separator: ";")
// let paraStr = AppDelegate.shareInstance().urlCommonParameters()!.replacingOccurrences(of: "?", with: "")
// return "\(cookieStr);device_info=\(paraStr)"
}
/**
解析全局JS对象
*/
func parseJSPageData(_ complete: @escaping ([String: AnyObject]) -> Void) {
webView?.evaluateJavaScript("window.GLOBAL.pagedata") { (object, error) in
if let data = object as? [String: AnyObject] {
complete(data)
}
debugPrint(error ?? "")
}
}
}
//
// GMWebViewComponent.swift
// Gengmei
//
// Created by Terminator on 2017/11/9.
// Copyright © 2017年 更美互动信息科技有限公司. All rights reserved.
//
import UIKit
import WebKit
import GMBaseSwift
import GMUtil
@objc protocol WKWebViewDelegate: class {
// 这是对外暴露的方法
@objc optional func handleLinkTap(_ url: String, host: String?, params: [String: AnyObject]?)
@objc optional func handleGlobalPageData(_ data: [String: AnyObject])
/// 数据请求成功h5调起
@objc optional func globalPageData(_ data: NSDictionary)
// 机构详情
@objc optional func globalDataLoaded(_ data: NSDictionary)
// 7770 i帖子头部切换
@objc optional func scrollSetHeader(_ data: NSDictionary)
// 导航栏隐藏显示
@objc optional func controlTitleBarVisible(_ show: Bool)
@objc optional func diaryDetailControllerShowNotificationAlert()
/// webView页面点击分享调起(没有share_data包裹)
@objc optional func webViewShareData(_ data: NSDictionary)
// 人脸分析之后点击分享传给客户端图片
@objc optional func shareFaceInfoImageMethod(_ imageString: String)
// 测肤分享图片传给客户端图片
@objc optional func shareSkinInfoImageMethod(_ imageString: String)
// 面孔起源分享图片传给客户端图片
@objc optional func shareResearchInfoImageMethod(_ imageString: String)
// 分享base64图片 {"imageString" : base64_String}
@objc optional func shareBase64ImageMethod(_ imageString: String)
// 工作台-面诊报告列表-投诉弹框
@objc optional func videoDiagnoseComplaint(_ data: NSDictionary)
// 保存视频方法
@objc optional func saveFaceVideo(_ jsonString: String)
// 播放视频方法
@objc optional func playFaceVideo()
// 是否展示空页面
@objc optional func showNativeEmptyView()
@objc optional func insurancePurchase(_ hasBought: Bool)
// 获取native本地公共参数
@objc optional func nativeDataLoaded() -> String
//获取用户信息
@objc optional func inflateUserInfo() -> String
// 实时获取数据返回值
@objc optional func onLineGetData(_ data: NSDictionary)
//修改用户头像
@objc optional func changeAvatar()
// 扫脸结果页获取im链接
@objc optional func consultationUrl(_ data: NSDictionary)
// 判断是否滑动到了底部
@objc optional func jsPageReachBottom(_ isScrollbottom: Bool)
// 测肤返回到首页
@objc optional func jsControlBackToMethod(_ jsonString: String)
// 扫脸页接口请求完成,隐藏loading
@objc optional func closeFaceLoading()
/// H5 指定分享平台
@objc optional func jsSharewithType(_ data: NSDictionary)
/// 回复弹框
@objc optional func jsShowActionSheet(_ data: NSDictionary)
// 面孔起源结果页跳转列表页
@objc optional func jsJumpToResearchPage(_ url: String)
// 精准曝光
@objc optional func hybridExposure(_ data: NSDictionary)
// 相机和麦克风权限
@objc optional func getVideoPermission(_ data: NSDictionary)
// 关闭视频面诊基本信息弹窗
@objc optional func closeCurrentPage()
// 视频面诊基本信息
@objc optional func showVideoBasicInfo(_ jsonString: String)
// 面诊记录列表查看评价与去评价
@objc optional func viewEvaluate(_ jsonString: String)
// 面诊记录列表查看投诉
@objc optional func viewComplaint(_ jsonString: String)
// 面诊订单列表确定订单
@objc optional func viewConfirm(_ jsonString: String)
// 面诊订单详情弹出投诉弹窗
@objc optional func showComplaint(_ jsonString: String)
// 展示评论列表
@objc optional func jsShowCommentList(_ string: String)
// 面诊弹窗
@objc optional func showCounsellorCard(_ string: String)
// 面诊弹窗全部卡片
@objc optional func showAllCard()
// 遮罩
@objc optional func showClientShadow(_ data: NSDictionary)
}
///考虑到要做成一个库不想要那么重的继承任务
@objcMembers
class GMWebViewComponent: UIView {
/// 事件
fileprivate weak var target: AnyObject?
///webcomponet
var webView = WKWebView()
/// 创建一个webiview的配置项
fileprivate let configuretion = WKWebViewConfiguration()
fileprivate let userContent = WKUserContentController()
fileprivate var showInputDic = NSDictionary()
var popupView: GMPopUpView!
var moreQueryParams = ""
var fullUrl = ""
var path = ""
/// 不立即请求
var isImmediateRequest = true
/// WebView配置项
var webEngine = GMWebEngine()
var clientH5Object = GMClientH5Object()
/// 进度条
var progressView: UIProgressView!
// 弹出键盘view
var showInputView = WMPostInputView()
//设置代理
weak var delegate: WKWebViewDelegate?
fileprivate var titleObserve: NSKeyValueObservation!
fileprivate var estimatedProgressObserve: NSKeyValueObservation!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
fileprivate func configure() {
}
//初始化Preferences
fileprivate func initPreferences() {
configuretion.preferences = WKPreferences()
configuretion.processPool = WKProcessPool.sharedProcessPool()
configuretion.preferences.minimumFontSize = webEngine.minFontSize
configuretion.preferences.javaScriptEnabled = webEngine.isAutomaticallyJavaScript
// 需要WKWebView支持页面内视频播放
configuretion.allowsInlineMediaPlayback = true
if #available(iOS 10.0, *) {
configuretion.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypes.init(rawValue: 0)
} else {
configuretion.mediaPlaybackRequiresUserAction = false
}
}
/**
初始化userContent
同步Ajax Cookie
*/
fileprivate func initUserContent() {
userContent.add(self, name: "gmclient")
let ajaxCookieScript = WKUserScript(source: webEngine.ajaxCookie(), injectionTime: .atDocumentStart, forMainFrameOnly: false)
userContent.addUserScript(ajaxCookieScript)
configuretion.userContentController = userContent
_ = webEngine.scriptMessageHandlerArray.map { [unowned self] (handlerName) in
self.userContent.add(self, name: handlerName)
}
}
func initProgressView() {
//进度条
progressView = UIProgressView(progressViewStyle: UIProgressViewStyle.bar)
progressView.progressTintColor = UIColor.mainVisual
addSubview(progressView)
progressView.snp.makeConstraints { (make) in
make.top.left.right.equalTo(0)
make.height.equalTo(1)
}
}
func initShowInputView(_ view: UIView) {
// 弹出键盘
showInputView = WMPostInputView()
showInputView.delegate = self
showInputView.isHidden = true
showInputView.removeFromSuperview()
view.addSubview(showInputView)
showInputView.snp.makeConstraints { (make) in
make.left.equalTo(0)
make.right.equalTo(0)
make.bottom.equalTo(0)
make.top.equalTo(OCNavigationBar.barHeight)
}
}
func initPopUpView(_ title: String) {
popupView = GMPopUpView()
popupView.delegate = self.delegate as? GMPopupBgViewDelegate
popupView.title = title
popupView.fullUrl = fullUrl
AppDelegate.visibleController.view.addSubview(popupView)
}
fileprivate func initWebView(_ webEngine: GMWebEngine) {
webView.removeFromSuperview()
webView = WKWebView(frame: CGRect.zero, configuration: configuretion)
webView.uiDelegate = self
webView.navigationDelegate = self
if #available(iOS 11.0, *) {
webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.never
}
//开启手势交互
webView.allowsBackForwardNavigationGestures = webEngine.isAllowsBackForwardGestures
//滚动条
webView.scrollView.showsVerticalScrollIndicator = webEngine.isShowScrollIndicator
webEngine.webView = webView
addSubview(webView)
//内容自适应
webView.snp.makeConstraints { (make) in
make.left.top.right.bottom.equalTo(0)
}
}
func wrapUrl() -> String {
var para = AppDelegate.shareInstance().urlCommonParameters()!
if fullUrl.isNonEmpty() {
if !fullUrl.contains("&device_id=") {
if fullUrl.contains("?") {
let startIndex = para.startIndex
let endIndex = para.index(startIndex, offsetBy: 0)
let range = startIndex...endIndex
para.replaceSubrange(range, with: "&")
}
fullUrl = "\(fullUrl)\(para)"
}
if self.moreQueryParams.isNonEmpty() {
fullUrl = "\(fullUrl)\(self.moreQueryParams)"
}
return fullUrl.trimSpace()
} else {
let apihost = GMServerDomains.apiHost!
let url = "\(apihost)/hybrid\(path)\(para)\(self.moreQueryParams)"
return url
}
}
///发送Request
public func sendRequest() {
let urlString = wrapUrl()
if urlString.isEmpty {
return
}
let url = URL(string: urlString)!
let urlHost = url.host ?? ""
let isAllow = GMServerDomains.allowURLHost(urlHost)
if isAllow == false {
#if DEBUG
UIAlertController.showOKAlert(withTitle: "webView需添加白名单")
#endif
return
}
let request = NSMutableURLRequest(url: url, cachePolicy: .reloadRevalidatingCacheData, timeoutInterval: 30)
request.setValue(webEngine.webCookie(), forHTTPHeaderField: "Cookie")
webView.load(request as URLRequest)
}
func webviewLoad(_ target: AnyObject) {
self.target = target
initPreferences()
initUserContent()
initWebView(webEngine)
initProgressView()
initShowInputView(self)
addObserver()
if fullUrl.isNonEmpty() || path.isNonEmpty() {
sendRequest()
}
}
/// 刷新
public func reload() {
//防止 登陆后缓存 修改不同步问题
let ajaxCookieScript = WKUserScript(source: webEngine.ajaxCookie(), injectionTime: .atDocumentStart, forMainFrameOnly: false)
self.userContent.addUserScript(ajaxCookieScript)
webEngine.syncCookies()
sendRequest()
webView.isUserInteractionEnabled = false
}
public func loadJsCode(jsCode: String) {
// 根据JS字符串初始化WKUserScript对象
self.webView.evaluateJavaScript(jsCode) { (value, error) in
debugLog(error)
debugLog(value)
}
}
/// 后退
public func goBack() {
webView.goBack()
}
/// 前进
public func goForward() {
webView.goForward()
}
/// 移除webView
public func removeWebView() {
webView.scrollView.delegate = nil
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: LOGIN_SUCCESS_NOTIFICATION), object: nil)
titleObserve?.invalidate()
estimatedProgressObserve?.invalidate()
userContent.removeAllUserScripts()
_ = webEngine.scriptMessageHandlerArray.map { [unowned self] (handlerName) in
self.userContent.removeScriptMessageHandler(forName: handlerName)
}
userContent.removeScriptMessageHandler(forName: "gmclient")
self.webView.navigationDelegate = nil
self.webView.uiDelegate = nil
}
override func willMove(toSuperview newSuperview: UIView?) {
if newSuperview == nil {
removeWebView()
}
}
func addObserver() {
titleObserve = webView.observe(\.title) { [unowned self] (_, _) in
guard let controller = self.target as? WMBaseViewController else {
return
}
controller.navigationBar.title = self.webView.title ?? ""
controller.title = self.webView.title ?? ""
}
estimatedProgressObserve = webView.observe(\.estimatedProgress, options: .new) { [unowned self] (_, change) in
if let currentProgress = change.newValue {
self.progressView.setProgress(Float(currentProgress), animated: true)
if Float(currentProgress) == 1 {
self.webView.isUserInteractionEnabled = true
}
}
}
NotificationCenter.default.addObserver(self, selector: #selector(reload), name: NSNotification.Name(rawValue: LOGIN_SUCCESS_NOTIFICATION), object: nil)
}
}
// MARK: - WKNavigationDelegate
extension GMWebViewComponent: WKNavigationDelegate {
///开始发送Request
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
debugLog("didStartProvisionalNavigation")
progressView.removeFromSuperview()
initProgressView()
progressView.isHidden = false
}
/**
Request请求完毕,内容开始返回
*/
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
debugLog("didCommitNavigation")
}
/// 页面加载完毕, 不一定及时得到数据
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webEngine.parseJSPageData { [weak self] (data: [String: AnyObject]) in
self?.delegate?.handleGlobalPageData?(data)
}
// 从H5中取得全局变量
delay(0.5) {
self.progressView.isHidden = true
}
}
/// URL重定向
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
guard let url = navigationAction.request.url else {
decisionHandler(.allow)
return
}
let urlHost = url.host ?? ""
// let dict = AppDelegate.navigation.visibleViewController?.getHostDictionary()
// let selector = dict?[urlHost] as? String ?? ""
if (url.scheme == URL_SCHEME) {
//更美协议
let urlStr = String(describing: url)
let encodeUrlScheme = urlStr.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
let encodeUrl = URL(string: encodeUrlScheme)
if encodeUrl == nil { return }
GMRouter.sharedInstance().pushScheme(encodeUrlScheme)
decisionHandler(.cancel)
return
} else if url.scheme == URL_HTTP_SCHEME || url.scheme == URL_HTTPS_SCHEME {
//正常http 请求 或者https请求
decisionHandler(.allow)
return
} else if url.scheme == "tel" {
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
UIApplication.shared.openURL(url)
}
decisionHandler(.allow)
return
} else {
let urlHost = url.host ?? ""
if !urlHost.isNonEmpty() {
decisionHandler(.allow)
return
}
let params = NSString(string: url.absoluteString).urlQueryToDictionary() ?? [:]
if self.delegate?.handleLinkTap?(url.absoluteString, host: urlHost, params: params as? [String: AnyObject]) != nil {
decisionHandler(.cancel)
return
} else {
decisionHandler(.allow)
return
}
}
}
//跳转失败的时候调用
public func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
progressView.isHidden = true
print(error)
}
// 内容加载失败时候调用
public func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
progressView.isHidden = true
print(error)
}
// 打开新窗口委托
public func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame?.isMainFrame == nil {
webView.load(navigationAction.request)
}
return nil
}
}
// MARK: - WKUIDelegate 不实现该代理方法 网页内调用弹窗时会抛出异常,导致程序崩溃
extension GMWebViewComponent: WKUIDelegate, WMPostInputViewDelegate {
// 获取js 里面的提示
public func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
let alert = UIAlertController(title: "提示", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "确定", style: .default, handler: { (_) -> Void in
completionHandler()
}))
alert.addAction(UIAlertAction(title: "取消", style: .cancel, handler: { (_) -> Void in
completionHandler()
}))
AppDelegate.visibleController.present(alert, animated: true, completion: nil)
}
// js 信息的交流
public func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
let alert = UIAlertController(title: "提示", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "确定", style: .default, handler: { (_) -> Void in
completionHandler(true)
}))
alert.addAction(UIAlertAction(title: "取消", style: .cancel, handler: { (_) -> Void in
completionHandler(false)
}))
AppDelegate.visibleController.present(alert, animated: true, completion: nil)
}
// 交互。可输入的文本。
public func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
let alert = UIAlertController(title: prompt, message: defaultText, preferredStyle: .alert)
alert.addTextField { (textField: UITextField) -> Void in
textField.textColor = UIColor.red
}
alert.addAction(UIAlertAction(title: "确定", style: .default, handler: { (_) -> Void in
completionHandler(alert.textFields![0].text!)
}))
AppDelegate.visibleController.present(alert, animated: true, completion: nil)
}
@objc(callPhone:) func callPhone(phone: String) {
var phoneStr = phone
if phone.contains("tel") {
phoneStr = phone.replacingOccurrences(of: "\"", with: "")
} else {
phoneStr = "tel:\(phone)"
}
if #available(iOS 10.0, *) {
UIApplication.shared.open(URL(string: phoneStr)!, options: [:], completionHandler: nil)
} else {
UIApplication.shared.openURL(URL(string: phoneStr)!)
}
}
@objc(showConfirm:) func showConfirm(jsonStr: String) {
let object = WMAlertParameterObject(string: jsonStr, error: nil)
if object != nil {
let alert = UIAlertController.showCustomAlert(withTitle: object!.title ?? "标题", message: object!.content ?? "内容")
alert.addAction(object?.confirmText ?? "确定") {
self.loadJsCode(jsCode: object?.confirmCallback ?? "")
}
alert.addAction(object?.cancelText ?? "取消") {
self.loadJsCode(jsCode: object?.cancelCallback ?? "")
}
}
}
/**
7715 以后统一弹起键盘事件
@param jsonString 回调方法和占位文字
*/
@objc(showInputView:) func showInputView(param: String) {
let data = param.data(using: String.Encoding.utf8)
if let dict = (try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers)) as? NSDictionary {
self.showInputDic = dict
self.showInputView.isHidden = false
// 帖子详情的全部评论回复需要限制字数
if AppDelegate.visibleController is GMTractateDetailController {
self.showInputView.textMaxCount = 50
}
self.showInputView.clear()
self.showInputView.placeHolder = String(describing: dict["placeholder"]!)
self.showInputView.show()
}
}
/// 弹起美分框
@objc(showTaskAlert:) func showTaskAlert(param: String) {
let data = param.data(using: String.Encoding.utf8)
if let dict = (try? JSONSerialization.jsonObject(with: data!,
options: .mutableContainers)) as? NSDictionary {
if dict.allKeys.count > 0 {
AppDelegate.shareInstance().showPointAlert(dict)
}
}
}
/// 未实名认证的code==70006,发送一个弹出认证页面的通知(前端判断70006时, 直接调用方法)
@objc(realNameAuthentication) func realNameAuthentication() {
NotificationCenter.default.post(name: Notification.Name(rawValue: PHONE_AUTHENTICATION), object: nil)
}
/// 回收键盘弹窗
func inputViewWillCancel(_ inputView: WMPostInputView!) {
self.showInputView.hide()
}
/// 键盘发送事件
///
/// - Parameters:
/// - inputView: 弹窗
/// - text: 发送内容
func inputView(_ inputView: WMPostInputView!, sendText text: String!) {
let a = NSString(string: String(describing: self.showInputDic["callback"]!))
let b = text.trimBothEnd() ?? ""
self.showInputView.hide()
self.showInputView.isHidden = true
let jsonStr = "window.gm.pack.run('\(a)', '\(b)')"
let result = NSString(string: jsonStr)
self.webView.evaluateJavaScript(result as String, completionHandler: nil)
}
/// 弹起全部回复
@objc(showPopupView:) func showPopupView(_ title: String) {
let data = title.data(using: String.Encoding.utf8)
let dict = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSDictionary
fullUrl = NSString(string: String(describing: dict!["fullUrl"] ?? "")) as String
let reply = NSString(string: String(describing: dict!["title"] ?? ""))
initPopUpView(reply as String)
}
/// 全部回复框动画完成
@objc(didCompletedAnimation) func didCompletedAnimation() {
let jsonStr = "window.gm.pack.run('refreshData')"
self.webView.evaluateJavaScript(jsonStr, completionHandler: nil)
}
}
// MARK: - WKScriptMessageHandler 对外暴露的方法
extension GMWebViewComponent: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if let dict = message.body as? [String: AnyObject] {
let method: String = dict["method"] as! String
let param = dict["param"]
// 带参数的情况
if param != nil {
let sel = "\(method):"
if clientH5Object.delegate != nil {
if clientH5Object.responds(to: Selector(sel)) {
clientH5Object.perform(Selector(sel), with: param)
} else {
if self.responds(to: Selector(sel)) {
self.perform(Selector(sel), with: param)
}
}
} else {
if self.responds(to: Selector(sel)) {
self.perform(Selector(sel), with: param)
}
}
} else {
let sel = "\(method)"
if (clientH5Object.delegate != nil) {
if clientH5Object.responds(to: Selector(sel)) {
clientH5Object.perform(Selector(sel))
}
} else {
if self.responds(to: Selector(sel)) {
self.perform(Selector(sel))
}
}
}
}
}
func showCommentList(_ string: String) {
self.delegate?.jsShowCommentList?(string)
}
@objc(showCounsellorCard:) func showCounsellorCard(_ string: String) {
self.delegate?.showCounsellorCard?(string)
}
@objc(showAllCard) func showAllCard() {
self.delegate?.showAllCard?()
}
@objc(jsObjShowShareView:) func jsObjShowShareView(with pageData: String) {
if pageData.isEmpty {
return
}
let data = pageData.data(using: String.Encoding.utf8)
let dict = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSDictionary
self.delegate?.webViewShareData!(dict!)
}
/// 数据加载完毕, 前端调用方法, 得到pagedata中数据
@objc(diaryGlobaltLoaded:) func diaryGlobaltLoaded(_ pageData: String) {
let Data = pageData.data(using: String.Encoding.utf8)
let dict = try? JSONSerialization.jsonObject(with: Data!, options: .mutableContainers) as! NSDictionary
self.delegate?.globalPageData!(dict!)
}
// 机构详情
@objc(globalDataLoaded:) func globalDataLoaded(_ pageData: String) {
let Data = pageData.data(using: String.Encoding.utf8)
let dict = try? JSONSerialization.jsonObject(with: Data!, options: .mutableContainers) as! NSDictionary
self.delegate?.globalDataLoaded!(dict!)
}
// 7770 帖子头部切换
@objc(scrollSetHeader:) func scrollSetHeader(_ JSONString: String) {
let Data = JSONString.data(using: String.Encoding.utf8)
let dict = try? JSONSerialization.jsonObject(with: Data!, options: .mutableContainers) as! NSDictionary
self.delegate?.scrollSetHeader!(dict!)
}
// true:导航栏显示 false:导航栏隐藏
@objc(controlTitleBarVisible:) func controlTitleBarVisible(_ pageData: String) {
let Data = pageData.data(using: String.Encoding.utf8)
let dict = try? JSONSerialization.jsonObject(with: Data!, options: .mutableContainers) as! NSDictionary
let show = dict?["show"] as? Bool
self.delegate?.controlTitleBarVisible!(show ?? false)
}
// 是否登录:1登录 0未登录
@objc(isUserLogin) func isUserLogin() -> Int {
let isLogin = GMLoginManager.shareInstance().isVisitor ? 0 : 1
let result = "window.gm.pack.run('isUserLoginCallback', '\(isLogin)')"
self.webView.evaluateJavaScript(result as String, completionHandler: nil)
return isLogin
}
@objc(jsPop:) func jsPop(_ isPop: Bool) {
if isPop {
DispatchQueue.main.async {
_ = AppDelegate.navigation.popViewController(animated: true)
}
}
}
@objc(domain) func domain() -> String {
return GMServerDomains.apiHost
}
@objc(showLoading) func showLoading() {
DispatchQueue.main.async {
AppDelegate.visibleController.showLoading("")
}
}
@objc(hideLoading) func hideLoading() {
DispatchQueue.main.async {
AppDelegate.visibleController.hideLoading()
}
}
@objc(playVideo:) func playVideo(_ JSONString: String) {
//Alert
if !JSONString.isNonEmpty() {
AppDelegate.visibleController.toast("视频无法播放")
return
}
let data = JSONString.data(using: String.Encoding.unicode)
do {
let dict = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! JsonType
let playFrom = dict["page_name"] as? String ?? ""
let topicId = dict["topic_id"] as? Int ?? 0
let businessId = dict["business_id"] as? Int ?? 0
let cardType = dict["card_type"] as? String ?? ""
let index = dict["index"] as? Int ?? 0
let currentTime = dict["currentTime"] as? Float ?? 0.0
let state = dict["state"] as? Int ?? 0
let playBackView = GMPlayerView()
playBackView.topicId = "\(topicId)"
playBackView.from = playFrom
playBackView.index = index
playBackView.needSkipSeconds = CGFloat(currentTime)
playBackView.playState = state
// 埋点使用
let video = GMVideoObject()
video.businessId = "\(businessId)"
video.pageName = playFrom
video.cardType = cardType
playBackView.video = video
if let playUrl = dict["url"] as? String {
playBackView.play(playUrl, animationRect: CGRect.zero)
}
} catch {
debugLog("track event error")
}
}
@objc(getAddressBook:) func getAddressBook(_ JSONString: String) {
DispatchQueue.main.async {
let manager = GMAddressManager()
manager.getAddressBookAuthorization()
}
}
@objc(chooseOneContactPerson:) func chooseOneContactPerson(_ key: String) {
let manager = GMAddressManager()
manager.getOneContactPersonBlock = { result in
if result != nil {
if let data = try? JSONSerialization.data(withJSONObject: result!, options: JSONSerialization.WritingOptions.init(rawValue: 0)) {
let jsParam = String(data: data, encoding: String.Encoding.utf8)
let jsonStr = "gm.util.setContactPerson('\(jsParam ?? "")')" //TODO 待调试
self.webView.evaluateJavaScript(jsonStr, completionHandler: nil)
}
}
}
manager.chooseContactPersonAddressBookJsonString()
}
@objc(share:type:) func share(shareDataString: String, type: String) {
// showAle
}
@objc(shareFaceInfoImageMethod:) func shareFaceInfoImageMethod(key: String) {
self.delegate?.shareFaceInfoImageMethod?(key)
}
// 人脸分析之后点击分享传给客户端图片
@objc(shareSkinInfoImageMethod:) func shareSkinInfoImageMethod(key: String) {
self.delegate?.shareSkinInfoImageMethod?(key)
}
// 人脸分析之后点击分享传给客户端图片
@objc(shareResearchInfoImageMethod:) func shareResearchInfoImageMethod(key: String) {
self.delegate?.shareResearchInfoImageMethod?(key)
}
@objc(shareBase64ImageMethod:) func shareBase64ImageMethod(key: String) {
self.delegate?.shareBase64ImageMethod?(key)
}
@objc(videoDiagnoseComplaint:) func videoDiagnoseComplaint(urlData: String) {
let Data = urlData.data(using: String.Encoding.utf8)
guard let dict = try? JSONSerialization.jsonObject(with: Data!, options: .mutableContainers) as! NSDictionary else { return }
self.delegate?.videoDiagnoseComplaint?(dict)
}
@objc(viewEvaluate:) func viewEvaluate(jsonString: String) {
self.delegate?.viewEvaluate?(jsonString)
}
@objc(viewComplaint:) func viewComplaint(jsonString: String) {
self.delegate?.viewComplaint?(jsonString)
}
@objc(viewConfirm:) func viewConfirm(jsonString: String) {
self.delegate?.viewConfirm?(jsonString)
}
@objc(showComplaint:) func showComplaint(jsonString: String) {
self.delegate?.showComplaint?(jsonString)
}
@objc(changeAvatar) func changeAvatar() {
self.delegate?.changeAvatar?()
}
@objc(jsControlBackToMethod:) func jsControlBackToMethod(key: String) {
self.delegate?.jsControlBackToMethod?(key)
}
@objc(jsJumpToResearchPage:) func jsJumpToResearchPage(url: String) {
self.delegate?.jsJumpToResearchPage?(url)
}
@objc(closeFaceLoading) func closeFaceLoading() {
self.delegate?.closeFaceLoading?()
}
@objc(showVideoBasicInfo:) func showVideoBasicInfo(key: String) {
self.delegate?.showVideoBasicInfo?(key)
}
@objc(getVideoPermission:) func getVideoPermission(_ pageData: String) {
let Data = pageData.data(using: String.Encoding.utf8)
let dict = try? JSONSerialization.jsonObject(with: Data!, options: .mutableContainers) as! NSDictionary
self.delegate?.getVideoPermission!(dict!)
}
@objc(showClientShadow:) func showClientShadow(_ pageData: String) {
let Data = pageData.data(using: String.Encoding.utf8)
let dict = try? JSONSerialization.jsonObject(with: Data!, options: .mutableContainers) as! NSDictionary
self.delegate?.showClientShadow?(dict!)
}
@objc(closeCurrentPage) func closeCurrentPage() {
self.delegate?.closeCurrentPage?()
}
@objc(consultationUrl:) func consultationUrl(_ urlData: String) {
let Data = urlData.data(using: String.Encoding.utf8)
guard let dict = try? JSONSerialization.jsonObject(with: Data!, options: .mutableContainers) as! NSDictionary else { return }
self.delegate?.consultationUrl?(dict)
}
@objc(saveFaceVideo:) func saveFaceVideo(key: String) {
self.delegate?.saveFaceVideo?(key)
}
@objc(playFaceVideo) func playFaceVideo() {
self.delegate?.playFaceVideo?()
}
@objc(openBrowser:) func openBrowser(urlStr: String) {
let alert = UIAlertController.showCustomAlert(withTitle: "提示", message: "你访问的网址将以外部浏览器打开,是否继续?")
alert.addAction("否", actionHandler: nil)
alert.addAction("是") {
if let url = URL(string: urlStr) {
if #available(iOS 10, *) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
UIApplication.shared.openURL(url)
}
}
}
}
@objc(jumpToLocationSettings) func jumpToLocationSettings() {
GMLocationManager.jumpToSettings()
}
@objc(locationShowAlertIfNotAllowed) func locationShowAlertIfNotAllowed() {
GMLocationManager.showAlertIfNotAllowed()
}
//把所有的js交互 鉴于实现代理 还是放在具体的业务中处理比较好
@objc(diaryDetailShowNotificationAlert) func diaryDetailShowNotificationAlert() {
//弹出通知提示页面
AppDelegate.shareInstance().userIsAllowPush { (status) in
let str = GMCache.fetchObject(atDocumentPathWithkey: kShowNotifyAlert) as? String ?? ""
if !str.isNonEmpty() && !status {
self.delegate?.diaryDetailControllerShowNotificationAlert!()
}
}
}
// 秒杀页面添加到系统日历事件 jsonString H5传来的的美购信息
@objc(remindEvent:) func remindEvent(jsonString: String) {
if let data = jsonString.data(using: String.Encoding.utf8) {
if let json = try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.init(rawValue: 1)) as? JsonType {
let beginTime = json!["start_time"] as? Double ?? 0
let endTime = json!["end_time"] as? Double ?? 0
let title = json!["title"] as? String ?? ""
let url = json!["url"] as? String ?? ""
let serviceId = json!["service_id"] as? String ?? ""
let isNotify = json!["notify"] as? Bool ?? false
let manager = GMCalendarEventManager()
manager.authorizationAllowed = { () in
let param = NSMutableDictionary()
param["service_id"] = serviceId
Phobos.track("activity_promotion_seckill_notice", attributes: (param as? JsonType ?? nil)!)
manager.addEvent(title, startDate: beginTime, endDate: endTime, serviceId: serviceId, url: url)
}
if manager.checkAuthorized() {
if isNotify {
let param = NSMutableDictionary()
param["service_id"] = serviceId
Phobos.track("activity_promotion_seckill_notice", attributes: (param as? JsonType ?? nil)!)
} else {
manager.removeEvent(serviceId)
}
}
}
}
}
// 保险回调
@objc(insurancePurchase:) func insurancePurchase(_ hasBought: NSNumber) {
self.delegate?.insurancePurchase!(hasBought.boolValue)
}
// 保险回调
@objc(jsPageReachBottom:) func jsPageReachBottom(_ isScrollbottom: NSNumber) {
self.delegate?.jsPageReachBottom!(isScrollbottom.boolValue)
}
@objc(sendMessage:body:) func sendMessage(phone: String, body: String) {
if GMMessageController.canSendText() {
let messageVC = GMMessageController()
messageVC.recipients = [phone]
messageVC.body = body
messageVC.modalPresentationStyle = UIModalPresentationStyle.fullScreen
AppDelegate.visibleController.present(messageVC, animated: true, completion: nil)
} else {
AppDelegate.navigation.toast("当前设备不支持发短信")
}
}
@objc(setHeaderHeight:) func setHeaderHeight(height: String) {
}
@objc(setLocalStorage:value:) func setLocalStorage(key: String, value: String) {
GMCache.storeObject(atDocumentPathWithkey: key, object: value as NSCoding)
}
@objc(getLocalStorage:) func getLocalStorage(key: String) {
let cacheValue = GMCache.fetchObject(atDocumentPathWithkey: key) as? String ?? ""
let str = "window.gm.pack.run('getLocalStorage','\(cacheValue)')"
self.webView.evaluateJavaScript(str) { (object, error) in
}
}
// 获取native本地公共参数
@objc(nativeDataLoaded) func nativeDataLoaded() {
let param = NSMutableDictionary(dictionary: NSDictionary.trackerPageParam(AppDelegate.visibleController))
param["title_bar_height"] = (OCNavigationBar.barHeight)
param["referrer_tab_name"] = AppDelegate.visibleController.referrerTabName
if let data = try? JSONSerialization.data(withJSONObject: param, options: JSONSerialization.WritingOptions.init(rawValue: 0)) {
if let jsParam = String(data: data, encoding: String.Encoding.utf8) {
self.webView.evaluateJavaScript("window.gm.pack.run('setNativeDataLoaded','\(jsParam)')", completionHandler: nil)
}
}
}
@objc(inflateUserInfo) func inflateUserInfo() {
if let str = self.delegate?.inflateUserInfo?() {
self.webView.evaluateJavaScript("window.gm.pack.run('setInflateUserInfo','\(str)')", completionHandler: nil)
}
}
@objc(logout) func logout() {
GMLoginManager.shareInstance().doLogoutAndShowLoginView()
}
//TODO
@objc(jsOpenAlbum:isPrivate:) func jsOpenAlbum(_ requestCode: String, isPrivate: Bool) {
}
@objc(trackEvent:) func trackEvent(_ JSONString: String) {
let data = JSONString.data(using: String.Encoding.unicode)
do {
let dict = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! JsonType
let params = dict["params"]
if params is String {
let objectData = (params as! String).data(using: String.Encoding.unicode)
let json = try JSONSerialization.jsonObject(with: objectData!, options: .mutableContainers)
Phobos.track(dict["type"] as? String ?? "", attributes: json as! JsonType)
} else {
let params = dict["params"] as? JsonType
if params != nil {
Phobos.track(dict["type"] as? String ?? "", attributes: (params ?? nil)! )
}
}
} catch {
debugLog("track event error")
}
}
@objc(showNativeEmptyView) func showNativeEmptyView() {
Phobos.track("on_click_button", attributes: ["page_name": AppDelegate.visibleController.pageName, "button_name": "click_reload",], sendNow: false)
self.delegate?.showNativeEmptyView?()
}
/// h5 实时调取 native 方法
@objc(onLineGetData:) func onLineGetData(_ pageData: String) {
let Data = pageData.data(using: String.Encoding.utf8)
guard let dict = try? JSONSerialization.jsonObject(with: Data!, options: .mutableContainers) as! NSDictionary else { return }
self.delegate?.onLineGetData?(dict)
}
@objc(sharewithType:) func sharewithType(with pageData: String) {
if pageData.isEmpty {
return
}
let data = pageData.data(using: String.Encoding.utf8)
let dict = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSDictionary
self.delegate?.jsSharewithType?(dict!)
}
// 跳转第三方APP
@objc(skipToThirdApp:) func skipToThirdApp(_ JSONString: String) {
let data = JSONString.data(using: String.Encoding.utf8)
guard let dict = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSDictionary else { return }
let urlStr = dict["target_url"] as! String
let url = NSURL.init(string: urlStr)! as URL
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
UIApplication.shared.openURL(url)
}
}
// 判断是否开启定位
@objc(isLocationEnable) func isLocationEnable() {
// WKWebview不支持直接传值,需要调H5的方法来传值给H5
self.webView.evaluateJavaScript("window.gm.pack.run('isLocationEnableCallback','\(GMLocationManager.hasOpenLocationService())')", completionHandler: nil)
}
// toast 弹窗
@objc(showToast:) func showToast(_ JSONString: String) {
let data = JSONString.data(using: String.Encoding.utf8)
guard let dict = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSDictionary else { return }
let text = dict["text"] as! String
if !text.isEmpty {
AppDelegate.visibleController.toast(text)
}
}
// 精准曝光
@objc(hybridExposure:) func hybridExposure(_ JSONString: String) {
let data = JSONString.data(using: String.Encoding.unicode)
do {
let dict = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! JsonType
Phobos.track("page_precise_exposure", attributes: dict, sendNow: true, currentAPI: GMExactExposureApi)
} catch {
debugLog("track event error")
}
}
}
// MARK: - 扩展WKProcessPool,使其变成单例,所有WKWebView共享Cookie数据
extension WKProcessPool {
static var SharedProcessPool: WKProcessPool = {
var sharePool = WKProcessPool()
return sharePool
}()
class func sharedProcessPool() -> WKProcessPool {
return SharedProcessPool
}
}
......@@ -5,7 +5,7 @@
// Created by wangyang on 16/7/8.
// Copyright © 2016年 更美互动信息科技有限公司. All rights reserved.
//
#import "WMBaseViewController.h"
/*** @brief 右按钮的 按钮类型 */
......
//
// WMTagView.swift
// test
//
// Created by wangyang on 15/12/8.
// Copyright © 2015年 Wanmiechuangyi. All rights reserved.
//
import UIKit
import SnapKit
//import GMBaseSwift
/*
高效的,可以在table及collectionView中使用的tagView。
现在用在了日记本卡片中,以保证首页流畅度。其它地方涉及需求时再改动
*/
@objcMembers
class WYTagView: GMView {
/// 在layoutsubview中使用该属性最后设置self的宽度
var maxWidth: CGFloat = Constant.screenWidth
var tapBlock: ((_ index: Int) -> Void)?
var tags: [String] = [] {
didSet {
for (index, view) in self.subviews.enumerated() {
let label = view as! GMLabel
// 如果视图的index超过数据的长度,则隐藏
if index >= tags.count {
label.isHidden = true
} else {
label.isHidden = false
label.text = tags[index]
}
}
}
}
override func layoutSubviews() {
super.layoutSubviews()
// 如果视图的right已经超过最大宽度,则隐藏
for (index, label) in self.subviews.enumerated() where label.frame.maxX > self.maxWidth {
// 经过产品王昕 确认iOS 如果超出显示...
if index > 0 {
label.isHidden = true
} else {
label.width = self.maxWidth
}
}
}
/// 在初始化方法
///
/// - Parameters:
/// - maxWidth: 最大宽度
/// - maxTagCount: 预估的tag label最大个数
/// - tagSpace: tag之间的距离
/// - customLabelUI: 自定义tag label的UI
convenience init(maxWidth: CGFloat, maxTagCount: Int, tagSpace: CGFloat, customLabelUI: ((GMLabel) -> Void)?) {
self.init()
self.maxWidth = maxWidth
// self不剪切,以显示全部的Label内容。见下面label.centerY的约束
clipsToBounds = false
var preLabel: UIView! = nil
for i in 0..<maxTagCount {
let label = GMLabel(frame: CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.bounds.size.height))
label.textColor = UIColor.mainVisual
label.font = UIFont.gmFont(13)
label.backgroundColor = UIColor.clear
label.layer.masksToBounds = true
addSubview(label)
label.snp.makeConstraints({ (make) in
if i == 0 {
make.left.equalTo(0)
} else {
make.left.equalTo(preLabel.snp.right).offset(tagSpace)
}
make.centerY.equalToSuperview()
})
preLabel = label
customLabelUI?(label)
}
// 点击手势:注意,是加在self上的,而不是每个label一个
let tap = UITapGestureRecognizer(target: self, action: #selector(WYTagView.tapAction(_:)))
addGestureRecognizer(tap)
}
@objc private func tapAction(_ tap: UITapGestureRecognizer) {
// 因为 pointInside:withEvent已经保证了是点击了tagView,那么剩下只需要判断点击的x是在哪个label范围就行了。
// 所以强制生成一个CGPoint(x: point.x, y: 0),只计算x范围
let point = tap.location(in: self)
for (i, view) in self.subviews.enumerated() {
if view.frame.minX < point.x && view.frame.maxX > point.x {
tapBlock?(i)
break
}
}
}
/// 为tag增加一点热区,主要是y方向,并且只在点击到了subview,才算作命中
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
if gm_point(inside: point, with: event) {
for view in self.subviews {
// 视图没有被隐藏,并且在视图的范围内
if !view.isHidden &&
view.frame.minX < point.x && view.frame.maxX > point.x {
return true
}
}
return false
} else {
return false
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment