iOS微信分享&h5和原生app交互
其实微信分享和微信支付要配置的东西差不多,而且在一个应用里面是用一个Appkey的不需要重新申请。而且代码中有很多重复的地方。
(一)分享
准备工作:注册微信Appkey
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[WXApi registerApp:@"wxd930ea5d5a258f4f" withDescription:@"测试demo"];
return YES;
}
2.构建微信分享的信息,调起微信SDK,跳转到微信
// [WXApi sendReq:req]; 打开微信
//分享文字给好友
SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init];
req.text = @"测试把信息分享到微信好友";
req.bText = YES;
req.scene = WXSceneSession;//会话(WXSceneSession)或者朋友圈(WXSceneTimeline)
[WXApi sendReq:req];
//分享图片给好友
WXMediaMessage *message = [WXMediaMessage message];
message.title = @"测试把图片分享到微信好友";
[message setThumbImage:[UIImage imageNamed:@"IconWX.png"]];
WXImageObject *imageObject = [[WXImageObject alloc] init];
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"IconWX" ofType:@"png"];
imageObject.imageData = [NSData dataWithContentsOfFile:filePath];
message.mediaObject = imageObject;
SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init];
req.bText = NO;
req.message = message;
req.scene = WXSceneSession;
[WXApi sendReq:req];
//分享网页给好友
WXMediaMessage *message = [WXMediaMessage message];
message.title = @"测试把web分享到微信好友";
[message setThumbImage:[UIImage imageNamed:@"IconWX.png"]];
WXWebpageObject *webObject = [WXWebpageObject object];
webObject.webpageUrl = @"http://www.baidu.com";
message.mediaObject = webObject;
SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init];
req.bText = NO;
req.message = message;
req.scene = WXSceneSession;
[WXApi sendReq:req];
//分享文字到朋友圈
SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init];
req.text = @"测试把信息分享到微信朋友圈";
req.bText = YES;
req.scene = WXSceneTimeline;//会话(WXSceneSession)或者朋友圈(WXSceneTimeline)
[WXApi sendReq:req];
//分享图片到朋友圈
WXMediaMessage *message = [WXMediaMessage message];
message.title = @"测试把图片分享到微信朋友圈";
[message setThumbImage:[UIImage imageNamed:@"IconWX.png"]];
WXImageObject *imageObject = [[WXImageObject alloc] init];
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"IconWX" ofType:@"png"];
imageObject.imageData = [NSData dataWithContentsOfFile:filePath];
message.mediaObject = imageObject;
SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init];
req.bText = NO;
req.message = message;
req.scene = WXSceneTimeline;
[WXApi sendReq:req];
//分享网页到朋友圈
WXMediaMessage *message = [WXMediaMessage message];
message.title = @"测试把web分享到微信朋友圈";
message.description = @"";
[message setThumbImage:[UIImage imageNamed:@"IconWX.png"]];
WXWebpageObject *webObject = [WXWebpageObject object];
webObject.webpageUrl = @"http://www.baidu.com";
message.mediaObject = webObject;
SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init];
req.bText = NO;
req.message = message;
req.scene = WXSceneTimeline;
[WXApi sendReq:req];
2.微信回调代理设置,打开你的app
//9.0前的方法,为了适配低版本 保留
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{
return [WXApi handleOpenURL:url delegate:self];
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{
return [WXApi handleOpenURL:url delegate:self];
}
//9.0后的方法
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options{
//这里判断是否发起的请求为微信支付,如果是的话,用WXApi的方法调起微信客户端的支付页面(://pay 之前的那串字符串就是你的APPID,)
//处理微信通过URL启动App时传递的数据,delegate代表在哪个类接收返回的请求,有时为了简化AppDelegate可以delegate设置为一个单利类,在单独的一个类处理微信回调的数据
//这个方法调起之后在点击返回商户之后会打开你的app,(对应第9步)
return [WXApi handleOpenURL:url delegate:self];
}
4.微信回调信息接收的地方
//微信SDK自带的方法,处理从微信客户端完成操作后返回程序之后的回调方法,显示分享结果
-(void) onResp:(BaseResp*)resp
{
if([resp isKindOfClass:[SendMessageToWXResp class]])
{
NSString *result = (resp.errCode == WXSuccess) ?KShareResultIsYes :KShareResultIsNo;
[[NSNotificationCenter defaultCenter] postNotificationName:KShareResultNotification object:result];
}
}
注:其实微信分享和微信支付在配置上很类似,微信分享的难点并不在这里,而是在于和h5界面的相互上。
(二)分享进阶:h5和原生app的交互
1.模拟情景:
1)app有一个模块是我的优惠券,这个优惠券的信息是UIWebView控件加载的h5界面,这些优惠券可以分享(转增)给我的朋友;
2)点击转增按钮,会打开微信客户端,将一条优惠券信息分享给我的朋友,
3)朋友在微信客户端点击之后,在微信的浏览器打开,然后可以领卷。
4)然后我在我的客户端可以查询到我的优惠券已经被朋友领取了,我的优惠券状态变为不可使用。
tips:需要注意的是分享分两种
1.分享给别人与自己无关
2.转增(分享)给别人,自己没有了
在第2种情况下分享信息给朋友并不是很难的部分,难点是如何和h5界面还有后端交互信息才是我们需要注意的地方。
2.转增优惠券流程展示
屏幕快照 2017-11-16 13.34.14.png3.实现原理
1.app截取webview的请求,经过判断发现是分享请求,就封装这条分享信息,调起微信Sdk,打开微信客户端进将这条信息分享给微信。
2.朋友接收到分享信息之后,在微信内置的浏览器中打开这个分享界面(h5),点击领取。
3.优惠券平台接收到优惠券已经被领取的信息后,修改优惠券状态。
4.当回到app时,重新加载h5界面。h5界面是由优惠券平台提供的数据,且在第三步优惠券的状态已经被改变了。
注:优惠券有3个状态: 1.可转增(可使用) 2.转增中(不可使用)3.已转增(不可使用)
4.ios代码实现
1.设置webview 加载网页
2.实现协议方法
3.实现网络截取后相应的方法
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
//获取自己的网络请求的网址字符串
NSString *urlString = [request.URL absoluteString];
//这个url字符串可能是
//自己定义的协议前缀 网页部分一会儿也是要设置成这个协议!
NSString *scheme = @"xmg://mailshare";
//打印出自己获取的网络请求的网址是什么
NSLog(@"~~~~~ %@",url);
//解析网址前缀是否为@"xmg://mailshare"
if ([url hasPrefix:scheme])
{
//在这里对截取到的信息进行处理,封装后,调起微信分享的SDK,进行分享,也就是第一部分的第二步
、、、、、、、、、、、、、、、、、、、、
//不加载这个网络请求的页面,返回NO,代表了这个对应的点击事件不由h5页面处理,而是交给了原生的app进行处理,
return NO;
}
//YES:加载这个网络请求的页面
return YES;
}
5.h5代码实现
屏幕快照 2017-11-16 14.03.18.png- 只需要在连接的地方,将href的改成自己设定的协议+方法名即可!
代码解释:
1.可交互前提:
iOS和h5界面的开发人员一起约定了xmg://mailshare代表了对应的按钮的点击事件是分享事件, 一般情况下来说NSString *urlString = [request.URL absoluteString];,这个urlString应该是“xml://mailshare+一个字典”,这个字典里面有这个按钮的相关信息,在ios端处理的时候一般是截取到最后一个字段,然后将这个字段的信息取出,在封装为分享的数据类型,然后传给微信。整个urlString都需要ios的开发人员和h5界面的开发人员约定好的。
(三)h5和原生app的交互
背景:
上面的交互只是单方面在OC处的webview协议方法解决,解析截取到的网络请求,这种方法实现起来比较快捷,但是JS得不到回执啦,
解决办法:
利用WebViewJavascriptBridge第三方库进行JS和OC的桥接
好处
利用桥接的话,就可以进行双方的通信,JS部分可以做回执处理,OC部分也可以做回执处理。 注意点就是JS的Handle要命名好,OC部分的Handle也要命名好,不要搞混淆。
1.ios端代码:
#import "ViewController.h"
#import "WebViewJavascriptBridge.h"
@interface ViewController ()<UIWebViewDelegate>
//声明`WebViewJavascriptBridge`对象为属性
@property (nonatomic,strong) WebViewJavascriptBridge * bridge;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void)viewWillAppear:(BOOL)animated{
if (_bridge) { return; }
//用UIWebView加载web网页
UIWebView * webview = [[UIWebView alloc]initWithFrame:self.view.bounds];
webview.delegate = self;
[self.view addSubview:webview];
//设置能够进行桥接
[WebViewJavascriptBridge enableLogging];
_bridge = [WebViewJavascriptBridge bridgeForWebView:webview];
[_bridge registerHandler:@"facebookObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@" ======FacebookObjcCallback ========= %@", data);
//传话给网页说已经接收到
responseCallback(@"facebookObjcCallback回复网页,已经收到消息");
//
}];
[_bridge registerHandler:@"QQShareObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@" ======QQShareObjcCallback ========= %@", data);
//传话给网页说已经接收到
responseCallback(@"QQShareObjcCallback回复网页,已经收到消息");
}];
[_bridge registerHandler:@"WXShareObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@" ======WXShareObjcCallback ========= %@", data);
//传话给网页说已经接收到
responseCallback(@"WXShareObjcCallback回复网页,已经收到消息");
//
}];
[_bridge registerHandler:@"MessageShareObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@" ======MessageShareObjcCallback ========= %@", data);
//传话给网页说已经接收到
responseCallback(@"MessageShareObjcCallback回复网页,已经收到消息");
//
}];
[_bridge registerHandler:@"MailShareObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@" ======MailShareObjcCallback ========= %@", data);
//传话给网页说已经接收到
responseCallback(@"MailShareObjcCallback回复网页,已经收到消息");
//
}];
// oc传话给JS(网页执行) 网页部分会执行以下代码:
/*
bridge.registerHandler('testJavascriptHandler', function(data, responseCallback) {
log('ObjC called testJavascriptHandler with', data)
var responseData = { 'Javascript Says':'Right back atcha!' }
log('JS responding with', responseData)
responseCallback(responseData)
})
接收
*/
//网页接收OC的方法句柄名叫testJavascriptHandler 此时OC给JS传的数据是@{ @"foo":@"before ready" }
[_bridge callHandler:@"testJavascriptHandler" data:@{ @"foo":@"before ready" }];
// 自定义按钮 此处没用,需要的可以自己打开使用
// [self renderButtons:webView];
//当你没有把网页放入服务器的话,可以把网页放在本地工程,这个时候就要执行以下的方法,用NSBoundle加载本地文件
// [self loadExamplePage:webview];
}
//自定义按钮
- (void)renderButtons:(UIWebView*)webView {
UIFont* font = [UIFont fontWithName:@"HelveticaNeue" size:12.0];
UIButton *callbackButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[callbackButton setTitle:@"呼叫JS的Handle" forState:UIControlStateNormal];
[callbackButton addTarget:self action:@selector(callHandler:) forControlEvents:UIControlEventTouchUpInside];
[self.view insertSubview:callbackButton aboveSubview:webView];
callbackButton.frame = CGRectMake(10, 400, 100, 35);
callbackButton.titleLabel.font = font;
}
//可以通过自定义按钮实现方法,动态和JS进行交互
//注:本代码中没有写按钮去实现此方法,需要的同学可以自己去定义按钮实现此方法
- (void)callHandler:(id)sender {
id data = @{ @"OC第一次发信息给JS": @"Hi there, JS,I am OC !" };
// testJavascriptHandler是JS部分接收OC传送消息的方法句柄
// data 是OC给JS传的数据
// response是JS接收到消息后给OC传的数据
[_bridge callHandler:@"testJavascriptHandler" data:data responseCallback:^(id response) {
NSLog(@"JS收到消息后,回复给OC的消息为: %@", response);
}];
}
//加载本地网页
//本代码中的网页是从服务器获取,不是放在本地,放在本地的同学,可以用以下的方法加载
- (void)loadExamplePage:(UIWebView*)webView {
NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"codetest" ofType:@"html"];
NSString* appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil];
NSURL *baseURL = [NSURL fileURLWithPath:htmlPath];
[webView loadHTMLString:appHtml baseURL:baseURL];
}
2.网页部分(JS部分)
①在script标签内写桥接方法
②在a标签内记得表面id唯一标示,以便script能够获取此标签元素
<script>
window.onerror = function(err) {
log('window.onerror: ' + err)
}
function setupWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
window.WVJBCallbacks = [callback];
var WVJBIframe = document.createElement('iframe');
WVJBIframe.style.display = 'none';
WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
document.documentElement.appendChild(WVJBIframe);
setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
}
setupWebViewJavascriptBridge(function(bridge) {
// JS注册接收消息的部分 名字叫testJavascriptHandler
// function是接收消息后做的处理
bridge.registerHandler('testJavascriptHandler', function(data, responseCallback) {
var responseData = { 'Javascript Says':'Right back atcha!'};
//给OC的消息回执
responseCallback(responseData);
});
document.body.appendChild(document.createElement('br'));
//facebook连接出发方法
var facebookButton = document.getElementById('Facebook');
facebookButton.onclick = function(e) {
e.preventDefault();
<!-- log('JS calling handler "FacebookObjcCallback"')-->
//桥接呼叫OC句柄:facebookObjcCallback
//并传送数据{'foo': 'bar'}过去
bridge.callHandler('facebookObjcCallback', {'foo': 'bar'}, function(response) {
//JS接收到OC的消息回执
<!--log('JS got response', response)-->
});
};
var QQShareBtn = document.getElementById('QQShare')
QQShareBtn.onclick = function(a){
a.preventDefault();
bridge.callHandler('QQShareObjcCallback',{'QQ':'share'},function(response){
});
};
var wxShareBtn = document.getElementById('WXShare')
wxShareBtn.onclick = function(a){
a.preventDefault();
bridge.callHandler('WXShareObjcCallback',{'WX':'share'},function(response){
});
};
var messageShareBtn = document.getElementById('MessageShare')
messageShareBtn.onclick = function(a){
a.preventDefault();
bridge.callHandler('MessageShareObjcCallback',{'Message':'share'},function(response){
});
};
var mailShareBtn = document.getElementById('MailShare')
mailShareBtn.onclick = function(a){
a.preventDefault();
bridge.callHandler('MailShareObjcCallback',{'Mail':'share'},function(response){
});
};
});
</script>
<div class="share_box row-eq-height">
<div class="share_box_bg">
<div class="col-xs-3 share_btn share_btn_left" style="">
來分享給好友! </div>
<div class="col-xs-9 share_btn">
<div id='log'>
<a href="" id='Facebook'> <img src="http://152.101.133.203:82/O2OBeauty/assets/images/invite_friend/invitefd_02-02.png"></a>
<a href="" id='QQShare'> <img src="http://152.101.133.203:82/O2OBeauty/assets/images/invite_friend/invitefd_02-03.png"></a>
<a href="" id="WXShare"> <img src="http://152.101.133.203:82/O2OBeauty/assets/images/invite_friend/invitefd_02-04.png"></a>
<a href="" id="MessageShare"> <img src="http://152.101.133.203:82/O2OBeauty/assets/images/invite_friend/invitefd_02-05.png"></a>
<a href="" id="MailShare"> <img src="http://152.101.133.203:82/O2OBeauty/assets/images/invite_friend/invitefd_02-06.png"></a>
</div>
</div>
</div>
</div>
学习博客:
http://blog.csdn.net/boring_cat/article/details/51240819