【iOS开发】仿微信分享功能

作者: 谦言忘语 | 来源:发表于2016-07-17 21:47 被阅读3241次

    目标

    本篇文章讲的是我做的一个仿微信分享到朋友圈的功能。
    事先声明,楼主并不知道微信的分享具体是怎么实现的,只是按照楼主自己的想法做了一个。而且,比较简陋。
    这篇文章主要是我上一篇文章的一个延伸。很多知识点在上一篇文章讲过了,这里就不再重复了。建议先看了上一篇文章再来看这篇文章。
    入口:【iOS开发】打开另一个APP(URL Schemes与openURL)

    实现过程

    • MyApp使用带了参数的url打开WXApp(微信APP)
    • WXApp在handleOpenURL回调中获取MyApp带过来的url
    • WXApp根据url的参数来跳转到朋友圈,并且给朋友圈分享内容。
    • 5秒之后,弹出alertView,选择是留在微信还是返回MyApp。
    • 根据用户的选择执行相应的动作。

    创建MyApp工程并做相应的设置

    • 创建一个名为“MyApp”的工程。这个工程是“我的APP”,是用来做分享用的。
      在Main.storyboard中添加一个button(分享到微信朋友圈),点击这个button就执行分享的方法。


      创建MyApp工程并添加button事件
    - (IBAction)sharedToPengYouQuan:(UIButton *)sender { 
        //创建一个url,这个url就是WXApp的url,记得加上://
        NSURL *url = [NSURL URLWithString:@"weixin://dl/moments?title=hello&content=helloworld&urlschemes=shixueqian"];
        
        //先判断是否能打开该url
        if ([[UIApplication sharedApplication] canOpenURL:url]) {
            //打开url
            [[UIApplication sharedApplication] openURL:url];
        } else {
            //给个提示或者做点别的事情
            NSLog(@"打不开weixin://。请检查有没有设置URL Schemes白名单或者有没有安装带有weixin://的应用");
        }   
    }
    

    这个方法只是创建了一个url,并且openURL。下面解析一下这个url的具体参数,

    • 使用weixin://这个URL Scheme来打开WXApp。
    • 使用weixin://dl/moments这个绝对路径来判断是否要跳转到朋友圈。
    • 使用title=hello&content=helloworld这两个参数来设置分享的内容。
    • 使用urlschemes=shixueqian来从WXApp跳转回MyApp。
    • 因为我们需要在分享完之后需要从WXApp跳转回来,所以需要设置URL Schemes,来让WXApp打开MyApp。
      步骤:选中MyApp工程->Info->URL Types->点击“+”->在URL Schemes栏填上 shixueqian
    设置URL Schemes

    这样WXApp就可以通过shixueqian://来打开MyApp了。

    • 设置URL Schemes白名单
      因为我们点击button的时候使用了canOpenURL:方法,故在iOS9环境需要设置URL Schemes白名单。
      步骤:点击info.plist文件->右键->Open As->Source Code->添加下面的代码
        <key>LSApplicationQueriesSchemes</key>
        <array>
            <string>weixin</string>
        </array>
    
    设置URL Schemes白名单

    OK,我们的MyApp已经完成了。

    创建WXApp工程并做相应的设置。

    • 创建一个名为“WXApp”的工程并在Main.storyboard中加一个label。表明这个是WXApp的主界面。


      创建WXApp工程并在主界面加个label
    • 设置URL Schemes。
      因为我们需要被MyApp打开的,所以需要设置URL Schemes来让别的APP打开。
      步骤:选中MyApp工程->Info->URL Types->点击“+”->在URL Schemes栏填上 weixin

    设置URL Schemes

    备注:
    在WXApp里面是不需要设置MyApp为URL Schemes白名单的。
    以真正的微信为例,微信分享和微信登录的开发者这么多,有这么多软件用到了这些功能,微信事先并不知道它们的URL Schemes。就算知道了,白名单最多只有50个,是远远不够的。所以是不会调用canOpenURL:方法来判断是否能打开的。
    那不先判断一下能否打开,假如微信打不开MyApp,苹果会不会拒绝微信上架呢?
    如果我是微信,我会采用了另外的方法来判断。
    我们知道,使用微信的分享功能必须要在微信开放平台上注册你的APP,微信开放平台会生成一个ID,你必须要设置微信给你的URL Schemes。假如你不设置,微信SDK就会报错。
    在这个前提下,有两种获取MyApp的URL Schemes的方式。

    • 方式一:MyApp使用分享功能打开微信App的时候,会把bundleID传过来的(回调方法中的sourceApplication),通过这个bundleID就可以从服务器上查到微信给你的URL Schemes。
    • 方式二:在打开微信APP的url中将MyApp的URL Schemes传过来。(微信应该会对这个URL Schemes进行验证的,我就不脑洞了)

    我们这个demo中用的是方式二,在url中当做参数将URL Schemes传过来。

    • 创建SQPengYouQuanController
      由于我们要跳转到朋友圈,所以要设置朋友圈控制器。
      创建SQPengYouQuanController,使用的是xib方式。
      在xib上加了几个label,并且把titleLabel和contentLabel作为SQPengYouQuanController的属性。这两个label的内容是通过MyApp传过来的url中的参数来设置的。


      设置朋友圈界面
    • 在SQPengYouQuanController.h中设置一个url属性
      这个url是MyApp传过来,用来设置titleLabel和contentLabel,并且设置返回MyApp。

    //  SQPengYouQuanController.h
    //  WXApp
    //
    //  Created by 石学谦 on 16/7/17.
    //  Copyright © 2016年 shixueqian. All rights reserved.
    #import <UIKit/UIKit.h>
    @interface SQPengYouQuanController : UIViewController
    
    //其他APP传过来的url,用来设置titleLabel和contentLabel,并且设置返回别的APP。
    @property (nonatomic, strong) NSURL *url;
    
    @end
    
    • 在SQPengYouQuanController.m中进行分享后的设置
      url传过来,我们可以利用url里面的参数对两个label赋值。并且根据url传过来的URL Schemes来跳转回MyApp。
    @implementation SQPengYouQuanController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        //设置分享后的内容
        [self displayWithURL:self.url];
    }
    
    //设置分享后的内容
    - (void)displayWithURL:(NSURL *)url {
        
        //获取url中的参数,转化为字典
        NSDictionary *params = [self getParamsWithURL:url];
        NSLog(@"dict=====\n%@",params);
        
        //给label设置值
        self.titleLabel.text = params[@"title"];
        self.contentLabel.text = params[@"content"];
        
        //延迟5秒再弹出alertView
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            //创建alertViewController
            UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"分享后的操作" message:@"是否返回原应用?" preferredStyle:UIAlertControllerStyleAlert];
            
            //返回按钮
            UIAlertAction *backAction = [UIAlertAction actionWithTitle:@"返回" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                //从字典中取出URL Schemes
                NSString *backURLString = [NSString stringWithFormat:@"%@://",params[@"urlschemes"]];
                NSURL *backURL = [NSURL URLWithString:backURLString];
                //跳转回MyApp
                [[UIApplication sharedApplication] openURL:backURL];
            }];
            [controller addAction:backAction];
            
            //留在微信按钮
            UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"留在微信" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                NSLog(@"留在微信");
            }];
            [controller addAction:cancelAction];
            
            //展示alertView
            [self presentViewController:controller animated:YES completion:nil];        
        });
    }
    
    //将url里面的参数转换成字典
    - (NSDictionary *)getParamsWithURL:(NSURL *)url {
        
        //query是?后面的参数,在这个demo中,指的是title=hello&content=helloworld&urlschemes=shixueqian
        NSString *query = url.query;
        
        //进行字符串的拆分,通过&来拆分,把每个参数分开
        NSArray *subArray = [query componentsSeparatedByString:@"&"];
        //把subArray转换为字典
        //tempDic中存放一个URL中转换的键值对
        NSMutableDictionary *tempDic = [NSMutableDictionary dictionary];
        
        for (int i = 0 ; i < subArray.count ; i++) {
            //通过“=”拆分键和值
            NSArray *dicArray = [subArray[i] componentsSeparatedByString:@"="]
            ;
            //给字典加入元素,=前面为key,后面为value
            [tempDic setObject:dicArray[1] forKey:dicArray[0]];
        }
        //返回转换后的字典
        return tempDic ;
    }
    
    @end
    

    大概分析一下这段代码:

    • viewDidLoad:中调用了displayWithURL :方法
    • displayWithURL :方法做了3件事:
      从URL中获取到参数,并转换成字典dict
      将字典dict中的title和content的值赋给titleLabel和contentLabel
      延迟5秒后弹出alertView,选择回到MyApp或者留在WXApp
    • getParamsWithURL:方法是将url里面的参数转换成字典,方便后面的处理

    在WXApp的appDelegete.m中做跳转的处理

    我们知道,在MyApp通过URL Schemes打开WXApp的时候,会调用appDelegate中的handleOpenURL:回调的。所以我们要在这个回调中获取到MyApp传过来的url,并且判断是否需要跳转到朋友圈。

    - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
        
        NSLog(@"url====%@\n sourceApplication====%@\n annotation===%@",url,sourceApplication,annotation);
        
        //判断是否要跳转到朋友圈
        if ([url.absoluteString hasPrefix:@"weixin://dl/moments"]) {
            //创建SQPengYouQuanController控制器
            SQPengYouQuanController *controller = [[SQPengYouQuanController alloc] initWithNibName:@"SQPengYouQuanController" bundle:nil];
            //给url赋值
            controller.url = url;
            
            //找出当前的控制器
            UIViewController *rootViewController = [[[UIApplication sharedApplication] keyWindow] rootViewController];
            //跳转到朋友圈
            [rootViewController presentViewController:controller animated:YES completion:nil];
            
        } else {
            //不是跳转到朋友圈
        }
        return YES;
    }
    @end
    

    分析一下这段代码:

    • 先判断是否要跳转到朋友圈,如果是weixin://dl/moments前缀的就跳转,否则不跳转。
    • 创建SQPengYouQuanController控制器,并将MyApp传过来的url赋值给SQPengYouQuanController中的url
    • 找出当前的rootViewController,并跳转到朋友圈

    好了,万里长征只差一步,运行。

    • 运行WXApp,会展示WXApp的主界面
    运行WXApp
    • 运行MyApp
    运行MyApp
    • 点击MyApp中的“分享到微信朋友圈”按钮,会跳转到WXAPP的朋友圈中,而且标题和内容都有了
    点击MyApp中的“分享到微信朋友圈”按钮
    • 5秒过后,会弹出一个提示框
    5秒过后,会弹出一个提示框
    • 点击“返回”后,会跳转回MyApp
    会跳转回MyApp

    好了,大功告成。

    备注:handleOpenURL回调中这样处理是有bug的,不知道大家发现了没?我就懒得处理咯,哈哈。

    参考

    本章的Demo已经上传到GitHub上面了。https://github.com/shixueqian/-IOS-
    详解URL的组成
    网络基础教程-http中url的组成和首部字段详解
    Objective-C中把URL请求的参数转换为字典
    非常有深度的讲解URL Shemes的文章:URL Schemes使用详解
    一些著名APP的URL Schemes:苹果app(iOS app)的URL schemes

    谦言万语

    别打赏,我要的是喜欢。

    相关文章

      网友评论

      • PGOne爱吃饺子:写的真不错,尤其是对那篇微信分享的原理,说的太好了,茅塞顿开啊,谢谢楼主,希望以后还能读到你的好文章。
      • 雨影:感觉微信分享之后返回的方法用的别的方法,因为微信分享完成返回之后跳转回原来的应用没有了左上角的app按钮(点击就返回原来的应用),但是我们如果用同样的openURL方法调用的话,就会有,还是说这个按钮可以选择显示和隐藏呢?
        谦言忘语:@雨影 。。。我试了,有的。手机系统为iOS10.3.3
        雨影:@谦言忘语 微信是没有的,我试过
        谦言忘语:你用简书的APP分享试试,只要是iOS9以上,都有的
      • dkStart:你好,我想请教下,微信分享回调,成功还是失败是如何判断的,我看了下微信分享成功后,返回app的url,只带了一个参数platformId=wechat。我有个想法,会不会是返回之后,微信的sdk自己再去通过网络访问去获取上次分享的结果。
        谦言忘语:这个我没有特意去看过。可以肯定的是,微信的重要参数并不是通过url来传递的。可能是使用了UIPasteboard的方式传递的。具体就不是很了解了
      • sunney0:您好,请问使用分享功能打开APP时候,,通过bundleID获取MyApp的URL Schemes的方式,怎么理解呀?比如我现在想用safari分享方式打开我自己的App,返回时怎么返回Safari,求指导,谢谢!有相关资料的话能给个链接么,谢谢。
        另:你文中的方式一 :grin:
        方式一:MyApp使用分享功能打开微信App的时候,会把bundleID传过来的(回调方法中的sourceApplication),通过这个bundleID就可以从服务器上查到微信给你的URL Schemes。
        谦言忘语:@sunney0 我的意思是:在MyApp打开WXApp的时候,在WXApp的-application:openURL:sourceApplication annotation: 方法中是可以得到MyApp的bundleID的。这个bundleID的值就在sourceApplication参数中。然后,我们通过这个bundleID来从服务器里面读取出来这个bundleID对应的app的URLSchemes(因为我们使用微信分享的话,注需要在微信开发者后台注册应用,然后微信会给你一个URLSchemes,让你配置到自己的app上面,所以你就有了微信给你的URLSchemes。微信就可以通过这个URLSchemes来打开Myapp了)。

      本文标题:【iOS开发】仿微信分享功能

      本文链接:https://www.haomeiwen.com/subject/gkqpjttx.html