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.png
3.实现原理

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容