注册
环信即时通讯云

环信即时通讯云

单聊、群聊、聊天室...
环信开发文档

环信开发文档

Demo体验

Demo体验

场景Demo,开箱即用
RTE开发者社区

RTE开发者社区

汇聚音视频领域技术干货,分享行业资讯
技术讨论区

技术讨论区

技术交流、答疑
资源下载

资源下载

收集了海量宝藏开发资源
iOS Library

iOS Library

不需要辛辛苦苦的去找轮子, 这里都有
Android Library

Android Library

不需要辛辛苦苦的去找轮子, 这里都有

Android V2.2.5 2015-12-31版本更新

 环信的小伙伴们,大家好。 2015-12-31 环信发布了最新的安卓SDK版本V2.2.5,大家可以关注一下,新版本的功能优化点如下:   1)实时通话新增弱网监测、暂停或打开音频视频流等API(相应增加的方法可查看文档)。 2)优化实时通话音质,完善了语...
继续阅读 »
 环信的小伙伴们,大家好。
2015-12-31 环信发布了最新的安卓SDK版本V2.2.5,大家可以关注一下,新版本的功能优化点如下:
 


1)实时通话新增弱网监测、暂停或打开音频视频流等API(相应增加的方法可查看文档)。
2)优化实时通话音质,完善了语音编码算法,提高了语音清晰度。 
3)在小米手机上,im离线时支持使用小米推送来进行消息的推送。
4)GCM优化,手机切到后台一段时间后,在支持GCM的app及手机上sdk会主动断掉和im长连接,
消息通过GCM推送到客户端,使手机更省电 。
5)修复实时通话对方拒绝时,有时候不显示拒绝的bug。
 


欢迎大家下载体验,下载地址http://www.easemob.com/downloads
 
使用过程中,有任何问题建议欢迎在下方评论直接回复留言! 收起阅读 »

教你如何从零开始,用环信ios sdk实现即时视频和聊天

先上效果图: 说说需求:开发一个可以进行即时视频聊天软件. 1. 最近比较忙,考完试回到公司就要做这个即时通信demo.本来是打算用xmpp协议来做视频通信的,想了想要搞后台,还要搭建服务器.一开始没明白是怎么样的一种形式.(现在想了想,其实就是...
继续阅读 »
先上效果图:

271180-95dcd33d9f72fb53-2.png




说说需求:开发一个可以进行即时视频聊天软件.
1. 最近比较忙,考完试回到公司就要做这个即时通信demo.本来是打算用xmpp协议来做视频通信的,想了想要搞后台,还要搭建服务器.一开始没明白是怎么样的一种形式.(现在想了想,其实就是自己写个服务器,然后放在服务器上而已了""脑袋被驴踢了).让后问boss服务器是我自己写还是怎样?然后boss让我先做个环信的demo,搞完再搞xmpp.


271180-738447d9a9e2d25a.png


[服务器的安装包]

2. 环信,什么鬼?
 - 1.集成IOS SDK前的准备工作: 
(如果需要推送消息,则要到苹果官网上制作证书,再到环信后台制作推送证书.
详细请看http://www.easemob.com/docs/ios/IOSSDKPrepare/#registerDeveloper)
注册环信开发者账号并创建后台应用,
登陆地址:https://console.easemob.com/?comeFrom=easemobHome
注册和登陆就不多说了,只介绍创建应用: 一般我们选择开放注册.
![创建应用]


271180-1dddbf42ba6c6d3c.jpeg



![得到appkey]


271180-cecf5150801dde87.png


 
   - 2.然后开始创建工程:
下载环信Demo及SDK:http://www.easemob.com/sdk/
解压缩iOSSDK.zip后会得到以下目录结构:


271180-caab5f8cb92c423b.jpeg



将EaseMobSDK拖入到项目中,并添加SDK依赖库


271180-c9c98270a35e53a5.jpeg



添加 以后,在AppDelegate中注册SDK

```
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary     *)launchOptions
{//registerSDKWithAppKey:为应用标示,apnsCertName为推送证书;(如果没用推送证书,这里可以随便)
    [[EaseMob sharedInstance] registerSDKWithAppKey:@"easemob-demo#chatdemo" apnsCertName:apnsCertName];
    // 需要在注册sdk后写上该方法
    [[EaseMob sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions];
    return YES;
}
```

3.下面我们开始主要界面的详解:
先上图吧.(因为视频通信需要两台真机,而我只能和iPhone对模拟器,所以没有视频图,但demo已经过测试可以视频聊天)
 - 1. 要进行对话,必须先有用户名,这样才能让对方找到你.(先注册,再登录.退出(用于测试))
![登录页面]

271180-a0f0c34d6cdc8d33.png



登录页面的代码比较简单.

    ```
           //异步注册账号
         [[EaseMob sharedInstance].chatManager asyncRegisterNewAccount:name.text
                                                             password:password.text
                                                       withCompletion:
         ^(NSString *username, NSString *password, EMError *error) {
             
             if (!error) {//注册成功,显示马上登录
                 UIAlertView* alert = [[UIAlertView alloc] initWithTitle:nil
                                                                 message:@"注册成功,请登陆"
                                                                delegate:nil
                                                       cancelButtonTitle:@"OK"
                                                       otherButtonTitles:nil];
                 [alert show];
                 alert = nil;
             }else{
                //输出错误信息.
             }
         } onQueue:nil];
//////////////////////////////////////////////////////////////////////
           
           // //异步登录账号
            [[EaseMob sharedInstance].chatManager asyncLoginWithUsername:name.text
                                                            password:password.text
                                                          completion:
         ^(NSDictionary *loginInfo, EMError *error) {
             
             if (loginInfo && !error) {
                 //设置是否自动登录
                 [[EaseMob sharedInstance].chatManager setIsAutoLoginEnabled:YES];
                 // 旧数据转换 (如果您的sdk是由2.1.2版本升级过来的,需要家这句话)
                 [[EaseMob sharedInstance].chatManager importDataToNewDatabase];
                 //获取数据库中数据
                 [[EaseMob sharedInstance].chatManager loadDataFromDatabase];
                 //获取群组列表
                 [[EaseMob sharedInstance].chatManager asyncFetchMyGroupsList];
             #warning 开始跳转,然后开始聊天
                 NSLog(@"登录成功");
                 TTAlertNoTitle(@"登录成功");
                 [self thisToChatViewController];
                 //发送自动登陆状态通知
                 //[[NSNotificationCenter defaultCenter] postNotificationName:KNOTIFICATION_LOGINCHANGE object:@YES];
                 
             }
             else
             {//输出错误信息.(太多,所以详见demo)
             }
         } onQueue:nil];

      ```

 - 2.登录后,有挺多的控件,
     - 1.返回键:点击时会调用-(void)dealloc方法,用做登出操作.
     - 2.UITextField: 你想要发送对象的名称,例如8080(下面将用8080做例子).
     - 3.send:建立一个与8080的会话.
     - 4.cheak:用于测试(现在没用了)
     - 5.hehe黄色的lable: 当有收到消息的时候,文字内容就会发生改变,显示还有多少条未读信息.
     - 6.最下面是UITableview,显示会话联系人.
![聊天列表]


271180-a5d5ab0f171b12b7.png




  
```
    首先要将代理设置好
    [[EaseMob sharedInstance].chatManager removeDelegate:self];
    //注册为SDK的ChatManager的delegate
    [[EaseMob sharedInstance].chatManager addDelegate:self delegateQueue:nil];
    [[EaseMob sharedInstance].callManager addDelegate:self delegateQueue:nil];
    //最后一个为即时通讯的代理,(即时视频,即时语音)

    当离开这个页面的时候,要讲代理取消掉,不然会造成别的页面接收不了消息.
    [[EaseMob sharedInstance].chatManager removeDelegate:self];
    [[EaseMob sharedInstance].callManager removeDelegate:self];

    这样以后,就可以使用代理方法来作一些事情了
    1.接收消息
    -(void)didReceiveMessage:(EMMessage *)message
    2. 未读消息数量变化回调
    -(void)didUnreadMessagesCountChanged
    3.实时通话状态发生变化时的回调,(如果没有实现这个函数,视频聊天邀请就会接收不到.)
    - (void)callSessionStatusChanged:(EMCallSession *)callSession changeReason:(EMCallStatusChangedReason)reason error:(EMError *)error
```

 - 3.(已经更新)因为是demo,就先用UITextView来显示对话,在UITextField中输入文字,点击send,即可发送,对方发送过来的内容也可以看到.点击视频聊天,大概要等5-10s对方才能收到请求.


271180-95dcd33d9f72fb53-2.png




```
   发送消息
-(void) send:(UIButton *)sender{
//         conversation= [[EaseMob sharedInstance].chatManager conversationForChatter:@"ozxozx" conversationType:eConversationTypeChat];
    
    
    EMChatText *txtChat = [[EMChatText alloc] initWithText:sendContext.text];
    EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithChatObject:txtChat];

    // 生成message
    EMMessage *message = [[EMMessage alloc] initWithReceiver:userName bodies:@[body]];
    message.messageType = eMessageTypeChat;
    

    EMError *error = nil;
    
    id chatManager = [[EaseMob sharedInstance] chatManager];
//    [chatManager asyncResendMessage:message progress:nil];
    [chatManager sendMessage:message progress:nil error:&error];
    if (error) {
        UIAlertView * a = [[UIAlertView alloc] initWithTitle:@"error" message:@"发送失败" delegate:nil cancelButtonTitle:@"好" otherButtonTitles:nil, nil];
        [a show];
    }else {
        textview.text = [NSString stringWithFormat:@"%@\n\t\t\t\t\t我说:%@",textview.text,sendContext.text];
    }
}
```

```
 //从会话管理者中获得当前会话.并将会话内容显示到textview中
-(void) addtext{
//1.
    EMConversation *conversation2 =  [[EaseMob sharedInstance].chatManager conversationForChatter:userName conversationType:0] ;
    NSString * context = @"";//用于制作对话框中的内容.(现在还没有分自己发送的还是别人发送的.)
    NSArray * arrcon;
    NSArray * arr;
    long long timestamp = [[NSDate date] timeIntervalSince1970] * 1000 + 1;//制作时间戳
    arr = [conversation2 loadAllMessages]; // 获得内存中所有的会话.
    arrcon = [conversation2 loadNumbersOfMessages:10 before:timestamp]; //根据时间获得5调会话. (时间戳作用:获得timestamp这个时间以前的所有/5会话)
// 2.
    for (EMMessage * hehe in arrcon) {
        id messageBody = [hehe.messageBodies firstObject];
        NSString *messageStr = nil;
//3.
        messageStr = ((EMTextMessageBody *)messageBody).text;
//        [context stringByAppendingFormat:@"%@",messageStr ];
        
        if (![hehe.from isEqualToString:userName]) {//如果是自己发送的.
            context = [NSString stringWithFormat:@"%@\n\t\t\t\t\t我说:%@",context,messageStr];
        }else{
            context = [NSString stringWithFormat:@"%@\n%@",context,messageStr];
        }
        
    }
    
    textview.text = context;
}
```
1 .EMConversation *conversation2 :会话对象,里面装着当前对话的双方的各种消息(EMMessage).
2 . EMMessage 消息.

```
 一个message的内容(对方发来的)
{"messageId":"83265683047055820","messageType":0,"from":"ozx8899","bodies":
["{\"type\":\"txt\",\"msg\":\"反对党\"}"]
,"isAcked":true,"to":"ozxozx","timestamp":1436951601011,"requireEncryption":false}
```

3.```((EMTextMessageBody *)messageBody)即为"bodies":["{\"type\":\"txt\",\"msg\":\"反对党\"}"]
即:消息为文本,信息内容为:反对党```


##视频聊天
```
-(void)openTheVideo:(UIButton *)btn{
    BOOL isopen = [self canVideo];//判断能否打开摄像头,(太多,详见demo)
    EMError *error = nil;
    EMCallSession *callSession = nil;
    if (!isopen) {
        NSLog(@"不能打开视频");
        return ;
    }
    //这里发送异步视频请求
    callSession = [[EaseMob sharedInstance].callManager asyncMakeVideoCall:userName timeout:50 error:&error];
    //请求完以后,开始做下面的
    if (callSession && !error) {
        [[EaseMob sharedInstance].callManager removeDelegate:self];
        CallViewController *callController = [[CallViewController alloc] initWithSession:callSession isIncoming:NO];
        callController.modalPresentationStyle = UIModalPresentationOverFullScreen;
        [self presentViewController:callController animated:NO completion:nil];
    }
    
    if (error) {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"error", @"error") message:error.description delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", @"OK") otherButtonTitles:nil, nil];
        [alertView show];
        alertView = nil;
    }
}
```

视频聊天的代码主要在CallViewController中.如果需要改变视频通话时的界面,就要改此控制器中的布局内容.
最要值得主要的是在dealloc函数中一定要加下面两句
```
[[EaseMob sharedInstance].callManager removeDelegate:self];
[[NSNotificationCenter defaultCenter] postNotificationName:@"callControllerClose" object:nil];
```
1.注销callManager的代理   2.通知消息中心,即时对话已经完成了
如果没有第二句,那么你的程序就只能进行一次即时通讯.
并且要在CallViewController将要返回的控制器中加上函数,注册当前控制器为callManager的代理.
```  
- (void)callControllerClose:(NSNotification *)notification
{
    [[EaseMob sharedInstance].callManager addDelegate:self delegateQueue:nil];
}
```

如果开发过程中遇到问题,不妨看看是不是两个主要的代理没有设定好:
[EaseMob sharedInstance].chatManager ; //这是会话管理者,获取该对象后, 可以做登录、聊天、加好友等操作
[EaseMob sharedInstance].callManager ;//这是即时通讯(语音聊天和视频聊天)的管理者.

demo可以在:https://github.com/ouzhenxuan/huanxinDemo 下载
使用前,请到http://www.easemob.com/downloads 把iOS版的SDK下载到工程中,即可使用 
简化版的demo:https://github.com/ouzhenxuan/shipinchat
如果感觉对你有帮助,请点个star.最近十分需要.你的star是我工作的支持. 收起阅读 »

火车票余票的查询+上拉加载,下拉刷新

上拉刷新,下拉加载demo。其中用到了MJRefresh第三方库,可以用于所有列表形式的刷新和加载,对于程序开发者具有很大的帮助; 使用方法:1.在ViewController中找到集成控件,设置刷新和加载时视图显示的提示信息 利用json解析网络接口,将解析...
继续阅读 »
上拉刷新,下拉加载demo。其中用到了MJRefresh第三方库,可以用于所有列表形式的刷新和加载,对于程序开发者具有很大的帮助; 使用方法:1.在ViewController中找到集成控件,设置刷新和加载时视图显示的提示信息
利用json解析网络接口,将解析出来的数据用视图显示出来,这里下拉刷新与上拉加载可以运用到多个地方,解决了数据一下子不能展示更多的缺陷
下面知识部分代码,其他代码已传到附件了
#import "AppDelegate.h"
#import "AppViewController.h"
@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.

AppViewController *tt = [[AppViewController alloc]init];


self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
self.window.rootViewController = tt;
[self.window makeKeyAndVisible];
return YES;
}

#import "AppViewController.h"
#import "CarViewController.h"
#import "AppDelegate.h"
@interface AppViewController ()

@end

@implementation AppViewController

- (void)viewDidLoad {
[super viewDidLoad];
CarViewController *tt1 = [[CarViewController alloc]init];

UINavigationController *nar = [[UINavigationController alloc]initWithRootViewController:tt1];
UIApplication *app = [UIApplication sharedApplication];
AppDelegate *app2 = app.delegate;
app2.window.rootViewController = nar;
}

#import "CarViewController.h"
#import "AppDelegate.h"
#import "CalendarHomeViewController.h"
#import "CalendarViewController.h"
#import "ChaViewController.h"
//CalendarMonthHeaderView.m
#import "Color.h"
#define WIDTH [[UIScreen mainScreen]bounds].size.width
#define HEIGHT [[UIScreen mainScreen]bounds].size.height
#define H [[UIScreen mainScreen]bounds].size.height/100
#define W [[UIScreen mainScreen]bounds].size.width/100

@interface CarViewController ()
{
UITextField *goText;
UITextField *toText;
CalendarHomeViewController *chvc;
UILabel *dateLable1;
NSString *strDate;
NSString *strWeek;
id obj;
//NSMutableString *isStr;

}

@end

@implementation CarViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.

// self.navigationController.navigationBar.backgroundColor = COLOR_THEME;
self.navigationController.navigationBar.barTintColor = COLOR_THEME;
self.navigationItem.title = @"车票查询";

self.view.backgroundColor = [UIColor colorWithRed:96.0/255 green:105.0/255 blue:144.0/255 alpha:0.31];
//出发点
goText = [[UITextField alloc]initWithFrame:CGRectMake(8*W, 20*H, 26.7*W, 7.5*H)];
goText.backgroundColor = [UIColor groupTableViewBackgroundColor];
goText.placeholder = @"出发地";
goText.font = [UIFont systemFontOfSize:24];
goText.textAlignment = NSTextAlignmentCenter;
goText.layer.cornerRadius = 10.0;
goText.delegate = self;
toText = [[UITextField alloc]initWithFrame:CGRectMake(66*W, 20*H, 26.7*W, 7.5*H)];
toText.backgroundColor = [UIColor groupTableViewBackgroundColor];
toText.placeholder = @"目的地";
toText.textAlignment = NSTextAlignmentCenter;
toText.font = [UIFont systemFontOfSize:24];
toText.delegate = self;
toText.layer.cornerRadius = 10.0;

[self.view addSubview:goText];
[self.view addSubview:toText];
//箭头
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(40*W,21*H, 19*W, 5*H);
[button setImage:[UIImage imageNamed:@"1"] forState:UIControlStateNormal];
[button addTarget:self action:@selector(change) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];

//选择日期

UIButton *but2 = [[UIButton alloc]initWithFrame:CGRectMake(0, 36*H, self.view.frame.size.width, 50)];
but2.backgroundColor = COLOR_THEME;
but2.titleLabel.textColor = [UIColor whiteColor];
but2.tag = 2;
//[but2 setTitle:@"选择日期" forState:UIControlStateNormal];
[but2 addTarget:self action:@selector(click:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:but2];


UILabel *dateLable = [[UILabel alloc]initWithFrame:CGRectMake( 8*W, 2*H, 22*W, 4*H)];
dateLable.text = @"出发日期";

dateLable1 = [[UILabel alloc]initWithFrame:CGRectMake( 40*W, 2*H, 60*W, 4*H)];

[dateLable1 setTextColor:[UIColor whiteColor]];
[dateLable setTextColor:[UIColor whiteColor]];
[but2 addSubview:dateLable];
[but2 addSubview:dateLable1];

//NSString *s = strDate;


//查询按钮

UIButton *but = [[UIButton alloc]initWithFrame:CGRectMake(37*W, 60*H, 100, 50)];
but.backgroundColor = COLOR_THEME;
but.titleLabel.textColor = [UIColor whiteColor];
[but setTitle:@"查询" forState:UIControlStateNormal];
[but addTarget:self action:@selector(cha) forControlEvents:UIControlEventTouchUpInside];
[but.layer setCornerRadius:10.0];
[self.view addSubview:but];

}
-(BOOL)textFieldShouldReturn:(UITextField *)textField{

[textField resignFirstResponder];
return YES;
}

-(void)change{

NSString *st1 = goText.text;
NSString *st2 = toText.text;

goText.text = st2;
toText.text = st1;
}

-(void)cha{
ChaViewController *cha = [[ChaViewController alloc]init];

cha.goStr = goText.text;
cha.toStr = toText.text;
cha.strDate1 = strDate;
cha.strWeek1 = strWeek;

[self presentViewController:cha animated:YES completion:nil];













}
-(void)click:(UIButton *)but
{

if (!chvc) {

chvc = [[CalendarHomeViewController alloc]init];

chvc.calendartitle = @"飞机";

[chvc setAirPlaneToDay:365*3 ToDateforString:nil];//飞机初始化方法

}

chvc.calendarblock = ^(CalendarDayModel *model){

NSLog(@"\n---------------------------");
NSLog(@"1星期 %@",[model getWeek]);
NSLog(@"2字符串 %@",[model toString]);
NSLog(@"3节日 %@",model.holiday);
strDate = [model toString];
strWeek = [model getWeek];
if (model.holiday) {

//[but setTitle:[NSString stringWithFormat:@"%@ %@ %@",[model toString],[model getWeek],model.holiday] forState:UIControlStateNormal];


dateLable1.text = [NSString stringWithFormat:@"%@ %@ %@",[model toString],[model getWeek],model.holiday];

}else{

//[but setTitle:[NSString stringWithFormat:@"%@ %@",[model toString],[model getWeek]] forState:UIControlStateNormal];
dateLable1.text = [NSString stringWithFormat:@"%@ %@",[model toString],[model getWeek]];
}
};

[self.navigationController pushViewController:chvc animated:YES];




}

收起阅读 »

入手环信,代码块知识点用的多,发帖回顾下

#import int c = 0; int main(int argc, const char * argv[]) {     @autoreleasepool {         //block声明格式:返回值类型 (^blaock名字) (形参列表...
继续阅读 »

#import

int c = 0;

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        //block声明格式:返回值类型 (^blaock名字) (形参列表)
        int (^myFun)();
       
        //block实现: block 名字 = ^(形参列表){};
        myFun =  ^(){
            NSLog(@"这是一个代码块");
            return 1;
        };
       
        //调用:block名称(实参列表),有返回值的block,可以用一个变量进行接收
        int a = myFun();//空括号不能少!!
       
        NSLog(@"%d",a);
       
        //有返回值,有形参,声明和实现放一起
        int (^myBlock)(int a, int b) = ^(int a, int b){
            return 1+b;
        };
        //调用
        int sum = myBlock(10,20);
        NSLog(@"%d",sum);
       
        //返回值类型是字符串 NSString *(^名字)(形参列表)
       
        NSString *(^myBlock1) (NSString *s) = ^(NSString *s){
            NSLog(@"字符串:%@",s);
            return s;
        };
        myBlock1(@"123");
       
        //有一个局部变量,要在block进行值的改变
       
        __block int b = 0;
       
        void (^myBlock2)() = ^(){
            b++;
        };
       
        //有一个全局变量,在block进行值的改变
       
        void (^myBlock3)() = ^(){
            c++;
        };
    }
    return 0;
}

block 作为函数参数
block作为形参使用,在函数中使用block方法运算数据
#import
//block作为函数的参数
//函数返回值类型  函数名(block的声明格式)
void fun(int (^bsasa)(int a,int b)){
    int sum = bsasa(3,2);
    NSLog(@"%d",sum);
}

void fun1(NSString *(^myBlock)(NSString *s),NSString *s1){
    NSLog(@"---%@",myBlock(s1));
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
       
        //当一个block作为函数的参数是,其返回值类型、形参个数及类型要与函数形参格式保持一致
        int (^myBlock) (int c, int d) = ^(int a, int b){
            NSLog(@"--%d,%d",a,b);
            return a-b;
        };
       
        //函数形参是block,调用时,直接传block的名字就行
        fun(myBlock);
       
        //调用的另一种方式:内联
        //内联block格式:^返回值类型 (形参列表){}
        fun(^int(int a, int b) {
           
            return a*b;
        });
       
       
        fun1(^NSString *(NSString *s) {
            return s;
        }, @"123");
       
    }
    return 0;
}
block作为方法的参数

Person.h
#import

//使用typedef声明block:typedef 返回值类型 (^名字)(形参列表)
typedef int  (^myblockType)(int a);

@interface Person : NSObject

//block作为方法的参数:(返回值类型 (^)(形参列表))参数名(blcok名字)
-(void)myblock:(int (^)(int a))block;

-(void)sengStr:(NSString *)name andblock:(NSString *(^)(NSString *))myblock1;

-(void)useblockType:(myblockType)sss;

-(void)myname:(NSString *)name;

@end
Person.m
#import "Person.h"

@implementation Person

-(void)myblock:(int (^)(int))block{
   
    int a = block(10);
    NSLog(@"%d",a);
}

-(void)sengStr:(NSString *)name andblock:(NSString *(^)(NSString *))myblock1{
    myblock1(name);
}

-(void)useblockType:(myblockType)sss{
    int res = sss(10);
    NSLog(@"---%d",res);
}

-(void)myname:(NSString *)name{
   
    NSString *str = [name stringByAppendingString:@"+-"];
    NSLog(@"%@",str);
}

@end
main.m
#import

#import "Person.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
   
        Person *p = [[Person alloc] init];

        [p sengStr:@"这儿" andblock:^NSString *(NSString *s) {
            NSLog(@"我在:%@",s);
            return s;
        }];//内联形式直接实现block、
       
        [p useblockType:^int(int a) {//typedef 声明
            return a;
        }];  
       
        //传入一个名字,然后进行拼接,名字--;
       
        [p myname:@"aa"];//
       
        [p sengStr:@"aa" andblock:^NSString *(NSString *s) {//
            return [s stringByAppendingString:@"--"];
        }];
       
    }
    return 0;
}
  收起阅读 »

基于react native 和 环信的实时通话的免费“店话” 项目 开源了

    基于react native 和 环信的实时通话的免费“店话” 项目开源啦! 用“店话”搜索想要找的店铺电话,也可以上传自己的店铺信息和在线的客户免费语音通话,语音通话的流量仅仅需要3-5kb/s啊,还不快快下载!   扫描二维码下载体验(ap...
继续阅读 »
 
 
基于react native 和 环信的实时通话的免费“店话” 项目开源啦!



用“店话”搜索想要找的店铺电话,也可以上传自己的店铺信息和在线的客户免费语音通话,语音通话的流量仅仅需要3-5kb/s啊,还不快快下载!
 



扫描二维码下载体验(apk在附件已上传,可以直接安装哦)



QQ截图20160106174752.png




源代码:https://github.com/vasth/dianhua(如果喜欢可以点下方赞赏按钮哦☺)

 
APP运行效果图展示:



Screenshot_2016-01-06-15-48-38-077_店话.png




Screenshot_2016-01-06-15-48-50-005_店话.png




Screenshot_2016-01-06-15-48-52-899_店话.png




Screenshot_2016-01-06-15-52-17-944_店话.png



 
点击下载APK  ↓
 
  收起阅读 »

ios简单的上拉刷新,下拉加载demo

ios简单的上拉刷新,下拉加载demo。其中用到了MJRefresh第三方库,可以用于所有列表形式的刷新和加载,对于程序开发者具有很大的帮助; 使用方法:1.在ViewController中找到集成控件,设置刷新和加载时视图显示的提示信息; 2.在设置刷新视图...
继续阅读 »
ios简单的上拉刷新,下拉加载demo。其中用到了MJRefresh第三方库,可以用于所有列表形式的刷新和加载,对于程序开发者具有很大的帮助; 使用方法:1.在ViewController中找到集成控件,设置刷新和加载时视图显示的提示信息; 2.在设置刷新视图中开辟线程的方法里设置刷新视图出现的时间长度; 3.在设置加载尾视图中设置加载时,将要增加的信息数量。 最后大家还可以根据自己的需求另作改动。


Simulator_Screen_Shot_2016年1月6日_下午1.07_.50_.png




Simulator_Screen_Shot_2016年1月6日_下午1.07_.59_.png


  收起阅读 »

看到很多人都急需一个ios简单集成 的demo ,这里就献丑上传一个

这个demo是按照视频http://v.youku.com/v_show/id_XMTQyMDc0NTQwMA==.html?from=y1.7-2  集成的,真的很简单...      项目已经上传到附件,感兴趣的可以下载看看,有不明白的可以在下面跟帖   ...
继续阅读 »
这个demo是按照视频http://v.youku.com/v_show/id_XMTQyMDc0NTQwMA==.html?from=y1.7-2  集成的,真的很简单...
 
   项目已经上传到附件,感兴趣的可以下载看看,有不明白的可以在下面跟帖
 
 
附件查看不到demo 的可以通过连接下载,下载地址:点击下载 收起阅读 »

iOS通过终端进行导入第三方库

iOS
这种方法是非常实用简单的,避免依次加入多个库    先确认电脑中是否安装有Ruby(ruby是安装cocoapods的前提)。 打开终端: 打开launchpad –其它-终端。 打开后 运行代码“rvm list”(查询已经安装的Ruby);如果先终...
继续阅读 »
这种方法是非常实用简单的,避免依次加入多个库
 
 先确认电脑中是否安装有Ruby(ruby是安装cocoapods的前提)。
打开终端: 打开launchpad –其它-终端。
打开后 运行代码“rvm list”(查询已经安装的Ruby);如果先终端列出了list得话说明Mac中已经安装了ruby 就可以直接安装cocoapods了。
记住到这的时候如出现在command not found:请阅读下面ruby安装文档,如果你的终端运行代码“rvm list”出现
rvm rubies

# No rvm rubies installed yet. Try 'rvm help install'.

scsysdeMac-mini-6:~ scsys$ :请跳过ruby安装
接下来就是你安装cocoapods,好了这是前期的工作,后面就是按照cocoapods文档中方法走吧
  收起阅读 »

Chatbox - 轻量级jQuery聊天窗插件

之前做WebIM的时候苦于没有现成的聊天窗组件,所以自己封装了一个jQuery插件。该插件仅仅只是一个前端组件,不涉及后端通讯。后端请自行实现,比如可以使用环信的IM云,后期我有空可以实现一个DEMO分享出来。 1. 轻量级动画特效以及友好的界面 2....
继续阅读 »

194137_o591_820321.png



之前做WebIM的时候苦于没有现成的聊天窗组件,所以自己封装了一个jQuery插件。该插件仅仅只是一个前端组件,不涉及后端通讯。后端请自行实现,比如可以使用环信的IM云,后期我有空可以实现一个DEMO分享出来。

1. 轻量级动画特效以及友好的界面
2. 支持多窗口和实例
3. 完善的回调函数以实现自定义功能
4. 多种调用方式
5. 良好的封装以及扩展性
6. 每个聊天窗对象实例以data属性的形式附加在聊天窗DOM对象上(如果你想获得某个特定插件的实例,可以直接从页面元素中获取:$('{boxId}').data('chatbox'))

项目地址:
http://haozki.me/Chatbox/
以上地址包含完整的API文档和Live Demo。可以直接看效果。

开源中国收录地址:
http://www.oschina.net/p/Chatbox

下载地址:
https://github.com/haozki/Chatbox/archive/master.zip
  收起阅读 »

score.js - jQuery星级评分插件

一年前写的jQuery星级评分插件,现在分享出来。代码不过200来行,有完善API文档说明。 1.完善的API 2.丰富的回调接口,实现灵活的功能控制 3.轻量级代码,使用更高效 4.支持自定义图标 5.支持Font-awsome扩展 项目...
继续阅读 »

195020_hyWh_820321.png



一年前写的jQuery星级评分插件,现在分享出来。代码不过200来行,有完善API文档说明。

1.完善的API
2.丰富的回调接口,实现灵活的功能控制
3.轻量级代码,使用更高效
4.支持自定义图标
5.支持Font-awsome扩展

项目地址:
http://haozki.me/score.js/
以上地址包含API文档和Live Demo。可以直接看效果。

开源中国收录地址:
http://www.oschina.net/p/score-js

下载地址:
https://github.com/haozki/score.js/archive/master.zip
  收起阅读 »

使用环信提供的EaseUI库集成客服demo

EaseUICustomer 使用环信提供的 EaseUI 库集成客服demo,方便开发者参考集成环信的客服功能;项目有详细的注释,适合新手以及老鸟参考研究, 此demo使用最新的环信提供的 EaseUI 库集成环信的客服聊天   源代码:https://g...
继续阅读 »
EaseUICustomer

使用环信提供的 EaseUI 库集成客服demo,方便开发者参考集成环信的客服功能;项目有详细的注释,适合新手以及老鸟参考研究, 此demo使用最新的环信提供的 EaseUI 库集成环信的客服聊天
 
源代码https://github.com/lzan13/EaseUICustomer
 
运行截图如下:



7RGANY[DGAF[[CML4ANAEC.jpg




`7A_91G_I(~1P~)1FLA7X2.png




24AOP1EC[9}0E8WLR5NG4L0.png




A{BZJ]KHU~F`VVT144@KR.png




TG6`TNGLNYJ@QX)F75FM]8O.png




R0BPRN91X)_L}1E~0U~YBI.jpg




U98IAWG0NTS8@BZTS95{2T.png




Z)~OL@W@VJPXRD@A7_NE}P0.png



关于EaseUI库

EaseUI 库可以去环信官网下载界面下载sdk,里边包含有EaseUI库 官网下载sdk
或者去环信的github上去下载:官网下载sdk

特点

使用了Android Material Design 样式开发,将Android新设计与环信的EaseUI结合,

需要注意的地方(重要)
使用时需要把配置文件里的appkey改成自己的,以及开屏页SplashActivity类里默认数据改成自己的 使用时需要把配置文件里的appkey改成自己的,以及开屏页SplashActivity类里默认数据改成自己的 使用时需要把配置文件里的appkey改成自己的,以及开屏页SplashActivity类里默认数据改成自己的 重要的事情说三遍 在使用过程中有什么疑问可以去环信官方社区 `imgeek.org` 去发帖[imgeek 社区][imgeek]
实现的功能

全局消息的监听,在DemoHelper类实现,搜索 onEvent 方法

通知栏消息提醒,这里使用 EaseUI 定义封装好的通知,这里只是稍微设置了下,单条消息会显示消息内容,多条消息会显示消息条数,以及小图标的设置

用户轨迹图文消息混排

满意度消息的收发

通知栏提醒

首先说下EaseUI重构客服demo的环境以及工具版本:
AndroidStudio version:1.5.0 SDKTools version:24.4.x Build-tools version:23.0.2 Compile SDK version:API 22(5.1) Minimum SDK version:API 15(4.0.3) Gradle version:2.4 jdk version:1.7
 
AndroidStudio等工具地址:

Android 官方下载  Android官网
国内网友收集 AndroidDevTools
Gradle(AndroidStudio有时自动下载不成功,所以要自己下载)  gradle v2.4下载 收起阅读 »

信息的分类,在做购物类的app很实用这个模块,将具有相同的特征信息进行归纳,类似于好友列表的原理

在iOS开发过程中我们经常用到将信息进行不同的分类,在淘宝上像将酒水,饮料,日常用品,家具等进行分类这就可以在一个viewcontroller里面编译,并且也可以获取点击事件通过不同的层数,知道哪个区域被点击,用起来非常的方便,这里已经封装这种方法的基本框架,...
继续阅读 »
在iOS开发过程中我们经常用到将信息进行不同的分类,在淘宝上像将酒水,饮料,日常用品,家具等进行分类这就可以在一个viewcontroller里面编译,并且也可以获取点击事件通过不同的层数,知道哪个区域被点击,用起来非常的方便,这里已经封装这种方法的基本框架,你只需要往框架里面填写信息就行了,以下注意事项;
   1.建一个你需要的viewcontroller,demo上是直接用ViewController,你需要导入MultilevelMenu文件
   2.接下来,就是你对数据的进行操作,最好是将你的数据通过字典,数组像结合进行整合,第二种方法就是通过plist文件进行操作,注意plist文件的操作,个人觉得plist高大上一点。
    3.就是将你的数据进行一层一层的解析,获取不同层次的方法:rightMeun * meun=[[rightMeun alloc] init]; meun.meunName = arr;//第一层获取 //酒水的分类 //日常用品分类//食品分类//水果 //饮料在这里我是简单用字典与数组进行数据处理:然后一层一层解析,具体的方法和怎么使用都在下面的demo中。
    4.在你使用之前,一定要将MultilevelMenu文件和Vendor文件加到工程中去,如果想改变cell的大小,菜单的颜色呀,你都可以在MultilevelMenu.h找到属性。效果图见附件和demo,工程中更加详细
 
收起阅读 »

用于聊天通讯录添加好友和删除好友的小demo

iOS
用到iOS中委托知识点把修改后的值传到原来的页面并更新主页面,   利用tableview进行显示通讯录列表,当点击某一个好友时,可以进入到详情进行编辑修改名称,然后把修改后的名称在显示到tableview 上面,当点击增加好友时可进入添加好友页面   ...
继续阅读 »
用到iOS中委托知识点把修改后的值传到原来的页面并更新主页面,
 
利用tableview进行显示通讯录列表,当点击某一个好友时,可以进入到详情进行编辑修改名称,然后把修改后的名称在显示到tableview 上面,当点击增加好友时可进入添加好友页面
 
 

收起阅读 »

一个基于公司招聘的小demo

iOS
用oc手工写的一个小的demo来实现的公司管理查询员工信息,输入公司的员工的名字就可以调出员工的个人信息,以及进行简历的筛选
用oc手工写的一个小的demo来实现的公司管理查询员工信息,输入公司的员工的名字就可以调出员工的个人信息,以及进行简历的筛选

好友列表展开、收起、点击修改、原理实现

好友列表,单独拉出来做了个文档,已上传。展开收起的实现其实是很简单的。首先我们把好友列表写在了UITableView 上,点击每个cell 可以触发 UITableViewDelegate 协议里面的 didSelectRowAtIndexPath:(NSIn...
继续阅读 »
好友列表,单独拉出来做了个文档,已上传。展开收起的实现其实是很简单的。首先我们把好友列表写在了UITableView 上,点击每个cell 可以触发 UITableViewDelegate 协议里面的 didSelectRowAtIndexPath:(NSIndexPath *)indexPath 这个协议方法跳转至下个界面查看并修改信息。而后在详情页即修改信息的控制器里面声明一个协议方法,-(void)editName:(NSString *)name andPhone:(NSString *)phone;  (可以再添加多个修改信息) [_delegate editName:nameText.text andPhone:phoneText.text]; // 实现修改     ,完成修改后,在委托者的控制器里面,这里是 ViewController,实现代理方法,并 [table reloadData]; // 刷新原数组显示。即可完成修改。同样在点击事件里,控制返回cell 行数,并 reloadData, 即可完成列表的展开、收起。 收起阅读 »

iOS集成支付宝

iOS
做了个文档传到附件了
做了个文档传到附件了

Ios上架流程

一、生成发布证书: 1、首先创建钥匙串配置文件,进入钥匙串 2、选择从证书颁发机构请求证书: 3、填写信息   4、保存配置信息 5、进入苹果开发者网页:https://d...
继续阅读 »
一、生成发布证书:

1、首先创建钥匙串配置文件,进入钥匙串


图片1.png


2、选择从证书颁发机构请求证书:


图片2.png



3、填写信息


图片3.png



 
4、保存配置信息


图片5.png


5、进入苹果开发者网页:https://developer.apple.com/
6、点击member center,如下图:


图片6.png


7、输入账号,进入开发者主页,并选择证书选项:


图片7.png


8、进入证书页,首先创建证书


图片8.png


9、选择production,并点击+

图片9.png


10、选择需要创建的证书类型,在这里我们选择production中的appstore and ad hoc,如果有推送功能,则重复以上步骤,选择第二个:


图片10.png


11、点击continu,直到进入Cenerate界面,点击choose file,上传之前创建好的


图片11.png


12、选择钥匙串授权文件,点击继续:


图片12.png


13、生成之后,我们会跳转到Download界面,点击界面中的“Download”下载下来,双击我们生成的.cer文件,一定要双击,双击后它会默认安装到钥匙串中。(推送证书重复之前步骤)
14、之后点击左边目录中的“Identifiers”下的“App IDs”,点击+:


图片14.png


15、填写创建证书所需要的信息(如果需要推送则选择第一个,固定标识):


图片15.png




图片16.png




图片17.png


16、点击continue,然后submit,如果有推送功能,则创建推送证书,创建推送证书过程中,会有个选择appids的选项,选择对应的appids:


图片18.png


17、注册手持设备,点击左边目录中的“Devices”,同样点击右上方的“十”号,进行添加。


图片19.png


18、输入设备名称以及udid,我们可以通过iTunes获取设备的udid:


图片20.png


19、点击continue,然后点击注册,完成设备的条件
20、创建Provisioning Profiles,也就是手机上使用的证书,点击最左边目录栏,选择“Provisioning Profiles”目录下的“All”,同样点击右上方的“十”号进入证书添加界面


图片21.png


21、选择APP Store,点击continue,选择我们之前创建的App ID,点击continue:


图片22.png


22、在下面选项里面选择我们之前生成的授权发布证书的名字,点击continue:


图片23.png


23、接下来输入证书名字,改名字将会在xcode中显示,然后点击Create来创建证书,最后下载,双击进行安装。
 

二、xcode打包发布的ipa
1、修改项目中TARGETS中的Bundle identifier,与我们之前创建的App ID中的标识保持一致:


图片24.png


2、分别设置TARGETS和PROJECT里面Build Settings中对应的Code Signing属性:


图片25.png


3、选择IOS Device,然后点击xcode菜单中的Product,选择Archive,进行打包:


图片26.png


4、打包完成后进入Archive界面,我们可以直接submit到appStore,也可以选择导出到本地,通过上传工具再上传:


图片27.png


5、点export,选择打包ipa的用途,我们选第一个,发布到appstore:


图片28.png


6、点击next,进入开发者账号的选择,如果之前设定好,会直接显示,反之则会提示输入账号和密码:


图片29.png


7、点击choose,会出现对应的应用信息,然后点击export,取个名字,直接保存即可
 

三、iTunes connect中创建app
1、进入苹果开发者网页:https://developer.apple.com/,进入member center,选择iTunes Connect:


图片30.png


3、点击+,选择新建IOS App,然后在弹出框填写自己的app信息:


图片31.png




图片32.png


4、点击创建,进入app详情页,上传自己的截图、app的展示图、app的描述等。
5:用application loader将ipa文件上传到iTunes connect,随后在app详情页的build处点击+,选择自己上传的ipa文件即可。
 
 
 
 
 
  收起阅读 »

iOS 通过 REST API 接口上传文件(图片)

官方文档中提到了通过通过 REST API 接口上传文件的问题。这里我简单介绍一下通过REST API 接口上传图片的问题。     我们知道由于iOS无法通过html表单来上传图片,因此想要上传图片,必须实现http请求,而不能像其他语言那样通过html表...
继续阅读 »


未命名.png


官方文档中提到了通过通过 REST API 接口上传文件的问题。这里我简单介绍一下通过REST API 接口上传图片的问题。
    我们知道由于iOS无法通过html表单来上传图片,因此想要上传图片,必须实现http请求,而不能像其他语言那样通过html表单的post就能上传。这个文档中貌似没有说清楚
上传图片的http post请求的格式是这样的:
    

11.png


第一行是指定了http post请求的编码方式为multipart/form-data(上传文件必须用这个)。 
boundary=AaB03x说明了AaB03x为分界线。比如 --AaB03x 就是一个分界线的意思 

content-disposition: form-data; name="field1" 

Hello Boris! 
 
 这句话声明了请求中的一个字段的名称,如field1  以及字段的值,如Hello Boris! 
这里类似form表单中的 
中间的空行是必须的。一般是文件的一些属性 

不同的字段之间用分界线分开,分界线需要单独一行,如 --AaB03x-- 

分界线的下一行,是下一个字段 

content-disposition: form-data; name="pic"; filename="boris.png" 
Content-Type: image/png 

... contents of boris.png ... 
--AaB03x-- 

这里声明了变量pic,也就是我们要传的文件,上传文件的时候需要在后边指定filename:filename="boris.png" 
并且需要在下一行指定文件的格式:Content-Type: image/png 

... contents of boris.png ...  这里是boris.png的二进制内容(也就是data类型),如 <89504e47 0d0a1a0a 0000000d 49484452 000000b4 000000b4 08020000 00b2af91 65000020 00494441 5478012c dd79b724 6b7616f6 8c888c88 8c9c8733 55ddb1d5 6a0db486 06218401 ...... 

在http post请求的结尾,需要有一个分界线,但是是前后都有--的:--AaB03x-- 

以上的这些格式,是http的规范,每个空行,空格都是必须的。 
 
下边是iOS的实现代码
/*---------------------------------上传图片-------------------------------------------*/

    //分界线的标识符
    NSString *TWITTERFON_FORM_BOUNDARY = @"AaB03x";
    //上传的接口
    NSURL *url = [NSURL URLWithString:@"https://a1.easemob.com/环信ID/APP名字/chatfiles"];
    //要上传的图片,得到data
    NSData *data = UIImagePNGRepresentation([UIImage imageNamed:@"defain"]);//这是我的本地图片
    //声明file字段,文件名为defain.png, 声明上传文件的格式
    NSString* strBodyBegin = [NSString stringWithFormat:@"--%@\nContent-Disposition: form-data; name=\"%@\"; filename=\"%@\"\nContent-Type: %@\n\n", TWITTERFON_FORM_BOUNDARY, @"file",  @"defain.png", @"image/png"];
    //声明结束符:--AaB03x--
    NSString* strBodyEnd = [NSString stringWithFormat:@"\n--%@--",TWITTERFON_FORM_BOUNDARY];
    NSMutableData *httpBody = [NSMutableData data];
    //表单开始
    [httpBody appendData:[strBodyBegin dataUsingEncoding:NSUTF8StringEncoding]];
    //填入数据
    [httpBody appendData:data];
    //表单结束
    [httpBody appendData:[strBodyEnd dataUsingEncoding:NSUTF8StringEncoding]]; 
/*
注意:这里我没有用下面的字段(它主要用来描述text格式的文本信息)
content-disposition: form-data; name="field1" 
Hello Boris! 
*/   
    NSMutableURLRequest* httpPutRequest = [[NSMutableURLRequest alloc] init];
    [httpPutRequest setURL:url];
    //设置请求方法
    [httpPutRequest setHTTPMethod:@"POST"];
    [httpPutRequest setTimeoutInterval: 60000];
    //设置HTTPHeader中token的值
    [httpPutRequest setValue:@"Bearer **************************************************" forHTTPHeaderField:@"Authorization"];
    //设置访问权限
    [httpPutRequest setValue:@"true" forHTTPHeaderField:@"restrict-access"];
    //设置Content-Length
    [httpPutRequest setValue:[NSString stringWithFormat:@"%@", @(httpBody.length)] forHTTPHeaderField:@"Content-Length"];
    //设置HTTPHeader中Content-Type的值
    [httpPutRequest setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",TWITTERFON_FORM_BOUNDARY] forHTTPHeaderField:@"Content-Type"];
    //将表单添加到请求体
    httpPutRequest.HTTPBody = httpBody;
    //异步请求
    [NSURLConnection sendAsynchronousRequest:httpPutRequest queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
       if (connectionError == nil) {
            id obj = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
            NSLog(@"服务器返回信息%@",obj);
        }
    }];
 
//服务器返回信息
2016-01-03 14:30:20.272 Fuhome-App[1356:154571] 服务器返回信息{
    action = post;
    application = "************";
    applicationName = **********;
    duration = 81;
    entities =     (
                {
            "share-secret" = "*********";
            type = chatfile;
            uuid = "***********";
        }
    );
    organization = ******;
    path = "/chatfiles";
    timestamp = 1451802620175;
    uri = "https://a1.easemob.com/******/*******/chatfiles";
}
 

      
  收起阅读 »

关于demo3.0表情,文字混合输入问题

在上一个2.0版本中,我有一天脑洞大开,突然想试试,聊天的输入内容是如何删除的。于是我输入了一些文字,发现删除时确实是一个一个删除的,接着测试,我在输入文字的同时,输入了表情,demo自带的表情。然后删除,发现也没问题。那么继续,我在输入文字时,夹杂了系统中得...
继续阅读 »
在上一个2.0版本中,我有一天脑洞大开,突然想试试,聊天的输入内容是如何删除的。于是我输入了一些文字,发现删除时确实是一个一个删除的,接着测试,我在输入文字的同时,输入了表情,demo自带的表情。然后删除,发现也没问题。那么继续,我在输入文字时,夹杂了系统中得emoji表情。然后,哈哈哈,程序跪了。查看代码后,发现一个emoji表情占两个字符,而是不是emoji表情居然是通过是否包含在_defaultEmoji进行的判断,而_defaultEmoji只包含demo自己的30多个表情,果然demo就是demo,参考一下就好。造成奔溃的原因就是我们输入了不属于_defaultEmoji的表情,在进行删除时,没有按两个字符进行删除。
#pragma mark - DXFaceDelegate

- (void)selectedFacialView:(NSString *)str isDelete:(BOOL)isDelete
{
NSString *chatText = self.inputTextView.text;

NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithAttributedString:self.inputTextView.attributedText];

if (!isDelete && str.length > 0) {
NSRange range = [self.inputTextView selectedRange];
[attr insertAttributedString:[EaseEmotionEscape attStringFromTextForInputView:str] atIndex:range.location];
self.inputTextView.text = @"";
self.inputTextView.attributedText = attr;
// self.inputTextView.text = [NSString stringWithFormat:@"%@%@",chatText,str];
}
else {
if (chatText.length > 0) {
NSInteger length = 1;
if (chatText.length >= 2) {
NSString *subStr = [chatText substringFromIndex:chatText.length-2];
if ([_defaultEmoji containsObject:subStr]) {
length = 2;
}
}
self.inputTextView.attributedText = [self backspaceText:attr length:length];
}
}

[self textViewDidChange:self.inputTextView];
}
解决也很简单,我再判断表情时,同时使用了下面的方法。这个方法我加在了NSString的扩展中。
+ (BOOL)stringContainsEmoji:(NSString *)string
{
__block BOOL returnValue = NO;

[string enumerateSubstringsInRange:NSMakeRange(0, [string length])
options:NSStringEnumerationByComposedCharacterSequences
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
const unichar hs = [substring characterAtIndex:0];
if (0xd800 <= hs && hs <= 0xdbff) {
if (substring.length > 1) {
const unichar ls = [substring characterAtIndex:1];
const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
if (0x1d000 <= uc && uc <= 0x1f77f) {
returnValue = YES;
}
}
} else if (substring.length > 1) {
const unichar ls = [substring characterAtIndex:1];
if (ls == 0x20e3) {
returnValue = YES;
}
} else {
if (0x2100 <= hs && hs <= 0x27ff) {
returnValue = YES;
} else if (0x2B05 <= hs && hs <= 0x2b07) {
returnValue = YES;
} else if (0x2934 <= hs && hs <= 0x2935) {
returnValue = YES;
} else if (0x3297 <= hs && hs <= 0x3299) {
returnValue = YES;
} else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) {
returnValue = YES;
}
}
}];

return returnValue;
}
注意:下面的代码为更新版本,上面的代码还是太久远了,下面的也是网上找到的,感觉还比较新。
+ (void)load {

    VariationSelectors = [NSCharacterSet characterSetWithRange:NSMakeRange(0xFE00, 16)];

}




- (BOOL)isEmoji {

    if ([self rangeOfCharacterFromSet: VariationSelectors].location != NSNotFound) {

        return YES;

    }

    

    const unichar high = [self characterAtIndex: 0];

    

    // Surrogate pair (U+1D000-1F9FF)

    if (0xD800 <= high && high <= 0xDBFF) {

        const unichar low = [self characterAtIndex: 1];

        const int codepoint = ((high - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;

        

        return (0x1D000 <= codepoint && codepoint <= 0x1F9FF);

        

        // Not surrogate pair (U+2100-27BF)

    } else {

        return (0x2100 <= high && high <= 0x27BF);

    }

}
收起阅读 »

如何通过REST接口获取token

/*--------------------------获取管理员oken---------------------------------------*/      NSURL *url = [NSURL URLWithString:@"https://a...
继续阅读 »
/*--------------------------获取管理员oken---------------------------------------*/
     NSURL *url = [NSURL URLWithString:@"https://a1.easemob.com/企业ID/应用app名称/token"];
     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
     request.HTTPMethod = @"POST";
     NSDictionary *body = @{@"grant_type":@"client_credentials",@"client_id": @"填写Client Id",@"client_secret":@"填写Client Secret"};
     [request setHTTPBody:[body JSONData]];//JSONData为一个库的方法,该库在下面附件中
     [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
     //连接,异步
     [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
     if (connectionError == nil) {
     id obj = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
     NSLog(@"服务器返回信息%@",obj);
     NSString* token = [obj objectForKey:@"access_token"];
     if(token)
     {
     //     access_token 保存一下(可以把token保存到本地)
     [[NSUserDefaults standardUserDefaults] setObject:token forKey:@"access_token"];
     [[NSUserDefaults standardUserDefaults] synchronize];
     }
     }
     NSLog(@"错误信息%@",connectionError);
     }]; 收起阅读 »

【有奖征集】环信开发文档Feedback

为了更好地解决开发者在集成环信产品时遇到的问题,降低使用难度。 我们专门开设一个帖子征集开发文档的不足之处。请大家不吝指正,毫无保留的提出意见和建议。 开发文档的地址是:http://docs.easemob.com 不管是界面,内容,还是结构。任何跟文档...
继续阅读 »
为了更好地解决开发者在集成环信产品时遇到的问题,降低使用难度。
我们专门开设一个帖子征集开发文档的不足之处。请大家不吝指正,毫无保留的提出意见和建议。

开发文档的地址是:http://docs.easemob.com

不管是界面,内容,还是结构。任何跟文档站相关的统统可以吐槽。我们将统一收集整理,并不断改进我们的产品。

当然,这一切也许还会有意想不到的惊喜哦~ 我们将对有价值的回复提供现金赞赏!

这种主动求吐槽,还派发奖赏的玩法好像也就我们一家了吧~

GO! GO! GO! 收起阅读 »

推荐一款编程字体,让代码看着更美

    在IDE(集成开发环境)中进行程序开发时,字体的选择看上去并不是那么的重要。但是,一款优雅的字体在整体视觉上能让代码看上去更美,营造一个积极的气氛,眼睛不再那么累,心情就会显得不错,那么你的开发效率自然也会有所提升。   今天,就给大家推荐一款字体,一...
继续阅读 »
 
 
在IDE(集成开发环境)中进行程序开发时,字体的选择看上去并不是那么的重要。但是,一款优雅的字体在整体视觉上能让代码看上去更美,营造一个积极的气氛,眼睛不再那么累,心情就会显得不错,那么你的开发效率自然也会有所提升。
 
今天,就给大家推荐一款字体,一款美美的字体,也是个人长久使用的字体。在这之前,先简单介绍一下Eclipse的默认字体 —— Consolas。既然被Eclipse选为默认字体,Consolas必然已经得到了广大编程人员的认可,优势之处无需多言,但美中不足的是,Consolas显示的中文比英文要小,如图所示:


1094967-49c4561e6be8713c.jpg


通常,为了便于操作,我们总是希望在PC一屏中显示更多的代码,于是便采取缩小字号的方式。但是,在Eclipse默认字体下,中文汉字、中文符号等就显得特别小以至于很难看清,眼睛非常之累。

相比之下,本文中的主角要出现了 —— YaHei.Consolas.1.12.ttf 。这是一款集成了微软雅黑的Consolas,非常漂亮,具体效果,有图有真相:


1094967-e0dbdbee5b20d42d.jpg


是不是有一种焕然一新的感觉呢?是不是显得特别大气呢?接下来就看一下在Eclipse中的安装教程吧。

首选下载 YaHei.Consolas.1.12.ttf 字体并复制到电脑控制面板中的字体目录下,Google Code 官方下载地址(翻墙):

https://code.google.com/p/uigroupcode/downloads/detail?name=YaHei.Consolas.1.12.zip&can=2&q=

CSDN资源下载地址:

http://download.csdn.net/detail/wenbitianxiafeng/9384674

在Eclipse中,选择[Windows] --> [Preference] --> [General] --> [appearance] --> [Colors and Fonts] --> [Basic] --> [Text Font],进入字体编辑窗口:

1094967-9c2edd5670821939.jpg


点击 [Edit],可以看到Eclipse默认的是Consolas字体:

1094967-b558b6e6c763601d.jpg


在字体列表中选中 YaHei.Consolas.1.12.ttf ,确定并应用即可。

然后就可以尽情的享受这款字体带来的愉悦吧。

PS:如果大家有更好的编程字体,欢迎评论推荐~ 收起阅读 »

ios详细的证书创建和上传

为新手制定一个详细的创建推送证书流程 第一步:生成.certSigningRequest证书 打开钥匙串,在钥匙串导航栏找到,“钥匙串访问”这一项,在钥匙串访问找到“从证书颁发机构请求证书”这一项,如图 点击后进入到如图界面 用...
继续阅读 »


为新手制定一个详细的创建推送证书流程
第一步:生成.certSigningRequest证书
打开钥匙串,在钥匙串导航栏找到,“钥匙串访问”这一项,在钥匙串访问找到“从证书颁发机构请求证书”这一项,如图

p1.png


点击后进入到如图界面

p2.png


用户电子邮件地址:写上你的邮件就行
常用名称:随便写
然后选择储存到磁盘,CA电子邮件地址不用写,点继续就生成了.certSigningRequest文件了,记得这个文件的储存位置,一会我们生成推送证书还要用到
第二步:创建推送证书
打开开发者中心,进入生成证书界面(应该找的到吧),进入之后,如果你要生成测试环境的推送证书,选择Certificates-Development,如果你要生成正式环境证书就选择Certificates-Priduction,这里我们以测试为例,点击右上角加号,如图

p3.png


进入下个界面,如果你要生成测试环境推送证书,就选择红色部分,你要生成正式环境证书,就选择绿色部分,如图

p4.png


点Continue,进入下个界面,让选择app id,提醒一下,选择app id要和你工程的Bundle Identifier对应,新手应该找的到Bundle Identifier吧,找不到看下面的图,我截了张图

p10.png


选择完app id ,一直点击Continue,进入如图界面

p5.png


让选择文件,还记得我们刚开始用钥匙串生成的.certSigningRequest在哪放着吧,就选择它就对了,选择完之后,接着往下面走,把证书下载下来之后,双击就放到钥匙串里面了,这时候推送证书就生成完了
第三步:生成p12文件
我们最终放到环信后台的证书是p12证书,打开钥匙串,找到我们刚才生成的证书,右键找到导出选项,如图

p6.png


点击导出“Apple Development.....”之后进入下个界面,如图:

p7.png


红色圈着的部分,储存为:里面要写上证书的名字,名字随便起,不过要记住这个名字,一会在环信后台上传证书还要用到这个名字,名字填完之后,点击储存,储存的位置要记住,一会还要用这个文件,这个文件就是我们要上传到环信的后台的p12文件,(储存的时候会让你输入密码,这个密码你要记住,一会上传到环信后台证书的时候要用到这个密码),这时候p12文件就制作完成了。
第四步:把p12文件上传到环信后台
打开我们的环信后台,找到 推送证书-ios,下面有上传证书的地方,如图

p8.png


证书名称:就是我们刚才生成p12的名称,我的叫zhuma_test
证书:就是我们刚才生成的p12证书,找到传上去
证书密码:生成p12证书的时候输入的密码(不是瞎输的吧,能记得吗,记不得重新导p12文件吧)
证书类型:我生成的是开发环境的证书,就勾选开发环境
填完之后就可以上传了,上传成功,就ok了 收起阅读 »

环信移动客服v4.2产品更新说明

环信移动客服v4.2 产品更新说明   新增功能   【客服系统】 多级会话标签 【数据统计】 聊天消息导出 【客服系统】 客服头像和企业logo 【客服系统】 访客超时未回复自动结束会话 【客服系统】 待接入筛选和搜索 【...
继续阅读 »
环信移动客服v4.2
产品更新说明
 

QQ截图20151229144613.png



新增功能
 
【客服系统】 多级会话标签
【数据统计】 聊天消息导出
【客服系统】 客服头像和企业logo
【客服系统】 访客超时未回复自动结束会话
【客服系统】 待接入筛选和搜索
【客服系统】 微博集成
【web插件】 访客端web插件开发者版
【客服系统】 会话显示关联名称
【客服系统】 自定义事件推送
【客服系统】 访客统计
【客服系统】 Android手机客服工作台新功能同步   
 
优化功能    
 
【web插件】 客服端增加ctrv+v图片预览
【客服系统】 欢迎语长度增加
【客服系统】 客服模式支持菜单收起
【数据统计】 历史会话支持模糊查询
【数据统计】 历史会话增加渠道、关联、评分等查询维度
【客服系统】 增加“系统开关”设置面板,统一管理系统开关
【客服系统】 优化文案
 
进入体验最新功能吧:  http://www.easemob.com/services

  收起阅读 »

在较成熟的中大型公司做创业项目,是种什么样的体验?

在体制发展较成熟的中大型公司里,搞创业项目,也是创业的一种姿态。     记得之前经常会碰到一些即将毕业的或者面临择业的朋友,会问到“依照现在国内互联网公司发展的情况,现在选择去一些较成熟的公司,如BAT这类的公司更好呢,还是选择去一些创业公司更好呢?”   ...
继续阅读 »
在体制发展较成熟的中大型公司里,搞创业项目,也是创业的一种姿态。  
 
记得之前经常会碰到一些即将毕业的或者面临择业的朋友,会问到“依照现在国内互联网公司发展的情况,现在选择去一些较成熟的公司,如BAT这类的公司更好呢,还是选择去一些创业公司更好呢?” 
 

                                   

banner_sample.png


 
 
很多专业的职业规划指导师,都会列出N条这样选择或者那样选择的优缺点,但是今天我想和大家分享另外一种工作的姿态,如标题所示。
 
什么样的公司称得上较成熟的中大型公司呢?这个当然也没有统一标准,不过按照目前国内互联网公司的现状来说的话,除了以BAT为首的大佬们,很多二三线的公司也称得上中大型公司,如网易、携程、美团、赶集网、新浪、搜狐等等;除了互联网行业,每个行业也有其龙头标杆,一般排在行业前5的公司,也可以算我要说的这种中大型企业;另外公司员工也可以作为参照,员工至少也是千人以上的级别。 
 
我所在的公司的是一家传统做软件外包服务的公司,员工近2000人,公司成立十年,业务发展稳定,在行业中也排的上前几。 
 
只是在这两年互联网发展如此迅猛的情况下,公司高层也一直谋划转型,希望做试水一些互联网的项目,因此我们的项目也在这种的情况下孵化了。 
 
我们产品叫摘客,是一款主推个性化推荐的互联网资讯聚合阅读产品,目前除了网站,iOS和Android版本的App也都已经上线。
 
摘客官网
 
言归正传,在这样的公司背景下,做这样一个未知的项目,体验可以分为以下几点: 
 
 1)生存问题没创业公司那么严峻 这一点可能也是唯一的好处啊,但它却是重要和必须的。显而易见,不太需要担心钱用完了,明天公司倒闭了这样的问题,因此在选择做与不做上,没有太多梦想与面包的挣扎; 
 
2)公司少数支持,资源匮乏 除了以上一点,貌似剩下的都是呕心沥血啊。大公司发展到这个地步,自然有它成熟的机制和业务发展模式,每个部门、岗位都仍然在它正轨上运行着;而你这样一样不合群新生的项目,自然在没有关系利益的时候,很难获得其他资源部门的支持;比如我们在APP,做网站的时候,需要界面UI设计,而我们核心的项目组成员保持为核心后台的开发,因此需要找我们公司UED项目组来合作;但是由于我们目前并不盈利,而高层也不可能来经常盯着这些事情,因此在和不同部门沟通协作的时候, 通常被作为优先级不高的、要求不高的事项,设计师自然也不会卖力做设计,这样的出品自然劳心劳力啊,吐槽一百遍~ 
 
3)没有经验积累 既然是创业项目,当然是和公司原先的业务发展不同,可想而知,公司在这项目方面的积累也是少之又少的。非常明显的一点,就是互联网产品的运营。由于公司之前都做的都是软件外包,公司的市场部也只要是针对2b的模式来做,完全不懂2C的玩法和运营。因此在完成产品的同时,运营的工作也成了我们项目的一大难题,由于没有经验可带队的人,我们运营都是从头开始,一路摸索而来,现在仍在继续抹黑爬行~~继续吐血~ 
 
4)发挥空间相对更多 相较于企业的传统业务和项目,创业型的项目在公司更有发挥空间。因为传统业务已经有较成熟的模式,分工细致,岗位明确,因此对于个人而言,在常规业务中想要争取向上层升职,也是较困难的。而在新兴项目中,基本都是空白,较容易成为第一个吃螃蟹的人。 
 
先写这些啦,其实在不同状态、环境下,都有来自各方无形的压力,写这些希望能分享给大家,纯属个人体验,欢迎交流分享~
 
下面分享我们产品的链接

                                   

最新二维码下载.png


 
  收起阅读 »

感恩有你,Merry Christmas

  因为有你,环信连接人与人才有价值。 因为有你,环信连接人与商业才有基础。 感谢有你,环信飞速发展,一年四轮融资。 感谢有你,环信即时通讯云稳居行业第一,移动客服领军行业。 感谢有你,环信大数据产品,反垃圾服务等如雨后春笋。 感谢有你,感恩有你,感激有你,“...
继续阅读 »
 
因为有你,环信连接人与人才有价值。
因为有你,环信连接人与商业才有基础。
感谢有你,环信飞速发展,一年四轮融资。
感谢有你,环信即时通讯云稳居行业第一,移动客服领军行业。
感谢有你,环信大数据产品,反垃圾服务等如雨后春笋。
感谢有你,感恩有你,感激有你,“环信”有“你”而精彩!
 
 
Merry Christmas
真诚的祝你圣诞快乐!

J{(}BNF76ZK0LDUV06X0R4M.jpg

收起阅读 »

【新特性】移动客服上线自定义富媒体消息的扩展功能

移动客服这边实现了自定义富媒体消息的扩展功能,允许客户为自己的客服坐席提供自 定义的包含图片,文字,链接等丰富内容的消息,用来向APP用户发送精美的产品介 绍,订单信息等等   简介 环信自定义消息API允许客户在坐席工作台加载自己的消息编辑页面,按照环信自定...
继续阅读 »
移动客服这边实现了自定义富媒体消息的扩展功能,允许客户为自己的客服坐席提供自
定义的包含图片,文字,链接等丰富内容的消息,用来向APP用户发送精美的产品介
绍,订单信息等等
 
简介
环信自定义消息API允许客户在坐席工作台加载自己的消息编辑页面,按照环信自定义消息的格式发送包含图文和链接的消息给访客,从而实现从坐席到访客的产品介绍,订单消息等丰富内容的可扩展消息。
 
使用场景:
开通自定义消息功能后,在消息编辑窗上方会增加自定义消息按钮:

图片1.png


 

点击自定义消息按钮,会弹出iFrame窗口并加载客户在开通功能时提供的的消息编辑页面

图片2.png


 

在编辑页面勾选消息,并确认发送后,消息会直接发送给访客,并显示在客服坐席的聊天记录窗口中。

图片3.png




图片4.png



 
访客APP一侧按照约定的消息格式做展示
 
与客服对话中的自定义消息:

图片5.png


 

点击打开后的自定义消息内容:

图片6.png


 

多个产品组合的购物清单:

图片7.png



新特性开通请联系“在线技术支持
新特性体验请点击“环信移动客服收起阅读 »

注册环信

我认为注册有两种方案,分别对应上图。 1.预注册一批账号备用。 这个方式主要是服务器端先注册一定数量的环信账号放到号码池,这样当用户注册时,可以直接从号码池分配,当号码池中的号码不足一定数量时,服务器再去注册,这样将用户中注册的流程分成了异步,提高了注册效率。...
继续阅读 »

注册账号.jpg


我认为注册有两种方案,分别对应上图。
1.预注册一批账号备用。
这个方式主要是服务器端先注册一定数量的环信账号放到号码池,这样当用户注册时,可以直接从号码池分配,当号码池中的号码不足一定数量时,服务器再去注册,这样将用户中注册的流程分成了异步,提高了注册效率。
2.直接注册。
这种方式就是当用户注册我的app时,我的服务器同步向环信注册。这样会增加客户端返回时间。
  收起阅读 »

【环信集成-入门篇】 环信能帮助我们做什么

作为一名常年混迹imGeek开发者论坛的程序猿,本着响应论坛号召的“我为人人,人人为我”口号,赠人玫瑰,手留余香。所以写下这期集成笔记,写这期笔记主要是为了让大家更直观的了解和解决大家的常见问题,比如:“环信是什么?我能不能使用?以及,怎么集成环信?”   ...
继续阅读 »
作为一名常年混迹imGeek开发者论坛的程序猿,本着响应论坛号召的“我为人人,人人为我”口号,赠人玫瑰,手留余香。所以写下这期集成笔记,写这期笔记主要是为了让大家更直观的了解和解决大家的常见问题,比如:“环信是什么?我能不能使用?以及,怎么集成环信?
 
先讲一下对环信的理解吧,其实我们可以把它想的简单一点。环信无非就是提供一个聊天通道,是吧,就这么简单的事。环信能帮我们干嘛呢?据说可以让APP、网站拥有微信、QQ 那样的通讯功能,可以让用户可以在自己的APP里发图片 文字语音等即时通讯功能。听起来是很高大上的,那我们就去看下环信能不能办到宣传的那样神奇 和究竟应该怎么使用这个”通道”吧。

官网文档是这样的

QQ截图20151224110147.png


 
求心里面的阴影面积呀,这也太繁琐了吧。不过为了这么高大上的功能花点时间研究也是值得的。
一个上午过去了,在怀着孜孜不倦的求知欲和技术支持团队可耐妹子的详细讲解下终于弄明白了

QQ截图20151224110416.png


大致分为了一下两步

1:客户端的集成
2:服务端的集成


客户端集成以 什么形式?有什么作用呢?
环信提供了原生的sdk ,Android iOS,webim ,需要把sdk导到自己的 项目,然后调用对应的api,比如登陆收发消息。

讲到这里,估计有的用户又有问题了,环信不是已经提供了聊天通道吗,为什么还要我们服务端集成呢?
这里需要注意的是环信“只是一个聊天通道”,不包含APP 的用户信息,也就是自己APP 的用户体系(昵称头像、好友备注分组等是需要自己维护的),所以这时候就需要服务端集成 了,集成的形式是写http请求,去调用环信restapi,不需要jar ,对语言没限制。
具体怎么做呢?这里我们把注册和登陆提出来重点讲一下
注册的流程:
用户在自己的应用里注册了账号,或者是已经上线的应用里面有了用户,现在需要使用环信im ,就需要服务端调环信rest接口为用户创建对应的im账号,调注册用户接口的时候传入的只有username和pwd,(建议加密过来,比如md5)调接口成功在response里会返回刚注册好的账号,自己服务器需要绑定起来把这个im账号与自己应用的账号对应。
登陆的流程:
用户在客户端登陆的是自己服务器,验证通过去拿到对应的im账号,再在客户端进行一个二次登陆,登陆环信的服务器,建立长连接。
当然,服务端的集成肯定不止这些,还可以对自己应用的im账号和群组进行关联,导出聊天记录等,具体的可以看看rest api文档。


这一期集成指南就介绍到这里吧,大家对环信有什么产品需求或者集成过程有什么建议可以在下方评论里留言。
  收起阅读 »

群组中如何使用@功能?

群组中,@某人的和群组普通消息没有区别,只是针对被@的用户在ui上显示会有不同。可以通过环信的扩展消息来实现。 1.发送方将想要@的人的环信id通过扩展字段放到扩展消息中,并把消息发到群里。 2.群中成员在收到消息时,先检查扩展字段中是否有对应的字段,如果有,...
继续阅读 »
群组中,@某人的和群组普通消息没有区别,只是针对被@的用户在ui上显示会有不同。可以通过环信的扩展消息来实现。
1.发送方将想要@的人的环信id通过扩展字段放到扩展消息中,并把消息发到群里。
2.群中成员在收到消息时,先检查扩展字段中是否有对应的字段,如果有,取出其中的环信id。
3.检查取出的环信id与当前登录的环信id是否一致。
4.如果检测一致,需要在ui上做特殊处理,显示出对应的提示信息,如“[有人@我]“,如不一致,不做处理。
 
发送方具体举例:
iOS:
message.ext = @{@"remindEId":@"6001"}
 
android:
message.setAttribute("remindEId","6001")
然后将消息发送出去。
 
接收方具体举例:
iOS:
-(void)didReceiveMessage:(EMMessage *)message{
    // 获取当前登录用户环信id
    NSString *currentUserId = [[[EaseMob sharedInstance].chatManager loginInfo] objectForKey: kSDKUsername];
    // 被@用户环信id
    NSString *remindEID = [message.ext objectForKey:@"remindEId"];
    if ([remindEID isEqualToString:currentUserId]) {
        // 当前登录用户被@,需要UI做单独处理
    }
}
 
android:
// 获取当前登录用户环信id
String currentUserId = EMChatManager.getInstance().getCurrentUser();
EMMessage message = EMChatManager.getInstance().getMessage(msgId);
// 被@用户环信id
String remindEID = message.getStringAttribute("remindEId")
if(remindEID==currentUserId){
    // 当前登录用户被@,需要UI做单独处理
 } 收起阅读 »

甲骨文收购StackEngine 提升云业务竞争力

12月23日消息,据华尔街日报报道,甲骨文最新的一笔收购虽然规模不大(涉及不到50名员工),但它可谓该公司重塑自我适应快速市场变化过程中迈出的重要一步。该数据库巨头上周五悄然收购了德州奥斯汀的创业公司StackEngine。   甲骨文未披露该交易的条款,但该...
继续阅读 »
12月23日消息,据华尔街日报报道,甲骨文最新的一笔收购虽然规模不大(涉及不到50名员工),但它可谓该公司重塑自我适应快速市场变化过程中迈出的重要一步。该数据库巨头上周五悄然收购了德州奥斯汀的创业公司StackEngine。
 
甲骨文未披露该交易的条款,但该收购将会有利于其具有重大战略意义的公共云业务的发展。

该集装箱运营平台将会促进甲骨文基于集装箱软件的新一代云服务的销售。前谷歌工程师、风投公司Accel Partners入驻创业者乔·布雷达(Joe Breda)指出,集装箱是计算机程序开发方式突变的一部分,给软件开发者带来了在大型网络上快速开发和推出软件的新途径。

该收购可能有助于甲骨文追赶其它在创业公司Docker崛起后十分看重集装箱技术的科技巨头。Docker于2013年年初以开源许可形式开放其集装箱技术,该概念由此开始普及。Docker产品高级副总裁斯科特·约翰斯顿(Scott Johnston)指出,在过去的一年里,包括IBM、VMware、微软和亚马逊在内的云计算提供商都曾推出基于Docker的软件与服务。

开发集装箱管理软件的创业公司Kismatic CEO帕特里克·雷利(Patrick Reilly)说道,“事实上,这些公司都在针对这一趋势进行投资,感觉大公司们都开始意识到该理念不同凡响了。”

甲骨文计划让StackEngine团队留在奥斯汀,其员工将在那里为甲骨文的云计算产品开发新功能。甲骨文云开发副总裁彼得·马格努松(Peter Magnusson)表示,StackEngine打造的集装箱管理软件将应用于甲骨文的集装箱服务,该类服务将“成为企业计算的重要部分”。

StackEngine的技术或许可帮助甲骨文的云服务吸引更多的企业客户。甲骨文在云领域的发展并不顺利,目前它的营收还主要依靠其它的业务。传统软件的许可和产品支持合约占该公司营收的70%。

在最近一个季度,甲骨文的新软件许可销售额同比下降18%。它的云计算业务收入为6.49亿美元,同比增长7%,但该增幅要远远落后于亚马逊。后者的云业务在最近一个季度实现了高达78%的增长。 收起阅读 »

一个IT人的职业规划

今年的校园秋季招聘已经进入尾声,计算机软件行业,作为每年校园招聘的重头戏,都会受到极大的关注。虽然阿里巴巴裁员、百度暂停校招的消息此起彼伏,但依旧无法阻止一大波鲜肉孤注一掷得注入互联网行业。同学们开始关注各大公司的官网,开始一遍遍得修改自己的简历,开始上网搜索...
继续阅读 »
今年的校园秋季招聘已经进入尾声,计算机软件行业,作为每年校园招聘的重头戏,都会受到极大的关注。虽然阿里巴巴裁员、百度暂停校招的消息此起彼伏,但依旧无法阻止一大波鲜肉孤注一掷得注入互联网行业。同学们开始关注各大公司的官网,开始一遍遍得修改自己的简历,开始上网搜索今年的面试经验,开始刷旧的笔试题目…… 
 
找工作的状态总的来说就是迷茫!迷茫!迷茫!实习中的状态总的来说就是心累!心累!心累! 
 
摘客作为贴心的公众号,为正在心累的工作瓶颈的同事们和还在迷茫和学校社会衔接处的同学们答疑解惑。 
 
主讲人李海峰的经历就是一个典型的IT人经历:从信息管理学院毕业,进入软件行业工作,从技术到管理层,又从管理层做精准技术,其中不断提升自己的英语水平,金融知识水平,自学机器学习。 
 
李海峰在自己的见解上介绍了计算机行业最基本的工作:开发/测试/PM的具体工作,也介绍了时下最容易入门,最热门的计算机语言。 
 
对于同学们的提问,李海峰都进行一一解答。作为一个成功的技术人和管理者,李海峰最大的收获就是要在每一次的转型中努力寻找到自己所喜欢做的事情,学习的过程也是以点成线,以线成面。 
 
最后借用王国维《人间词话》的内容来总结海峰分享给大家的学习之道: 
“古今之成大事业、大学问者,必经过三种之境界: 
‘昨夜西风凋碧树。独上高楼,望尽天涯路。’此第一境也。 
‘衣带渐宽终不悔,为伊消得人憔悴。’此第二境也。 
‘众里寻他千百度,蓦然回首,那人却在,灯火阑珊处。’此第三境也。” 
 
 以下为李海峰演讲实录: 
 
大家晚上好,我是来自浙江网新恒天软件有限公司大数据项目组的技术负责人李海峰,今天由我给大家分享一个IT人的职业生涯规划。 我从信息管理学院毕业,进入软件行业工作,从技术到管理层,又从管理层做精准技术,其中不断提升自己的英语水平,金融知识水平,自学机器学习。在过程中我就是在不断得寻找自己喜欢的东西,并且坚持做下去。 
 
接下来我来讲讲一个软件公司最多的职业,开发。对开发的要求,不外乎下面几个:具有完整设计一个中型项目的能力;深入理解其所使用工具的原理,熟练使用各种标准类库或第三方类库;独立完成多个项目或多个Release的核心模块;代码质量优异,Debug能力强;系统设计和开发中具备很强的创新能力;具有带领团队进行技术攻关的能力。在刚刚进入公司的时候,我建议大家至少要熟练掌握一种语言,多学习。正常的情况下,用3年的时间就可以把自己锻炼成一个高级软件工程师。 
 
然后是相对较多的一个职业,测试。对测试的要求是这样的:具有一定的测试规划和管理能力;深入理解软件测试过程,具有制定和改进软件测试过程的能力;具有较强的代码、文档审查能力;深入理解各种软件测试工具,并能熟练应用;对软件度量有一定的理解,具有较强的软件测试分析和设计能力;具有带领团队进行相关测试工作的能力。所以测试需要有一定的文档的编辑能力,同时需要具有比较好的交流能力,因为需要和客户方进行软件功能上的交流。 
 
大家应该都很关心什么时候可以做一个program manager,但做PM的要求不仅像做一个开发工程师,首先需要可以搞定客户,对需求进行分析,制定实现方案,对项目的预期管理,从接触到合同到上线都要全程把关;同时要管理团队,包括对一个团队的组建,调节团队氛围,在成员出现矛盾时做一个救火队长。作为一个PM必须要做到的是先做人,再做事! 
 
 接下来给大家分享一下现在比较热门的语言:
 | Java 仍然是主流,应用越来广泛,非常适合作为基础语言学习。强烈推荐大家学习
 | Python 胶水语言,各个语言的粘合剂。在大数据时代也是数据分析基础语言,如对数据分析挖掘感兴趣,推荐学习。 
 | PHP 网站快速开发的不二选择,在互联网+创业的高潮,PHP人才的薪水是涨幅最快的。
 | JS 前端语言,HTML5未来有更广阔的应用空间,对前端有兴趣的尽量学好。 
 | OC 只能应用在苹果平台,比较局限,建议慎重选择。 
 | Scalla 函数式编程的代表语言,spark上的主流开发语言。不过只能打辅助,不能当Carry,可以做为学好Java后的一个补充。
 | Shell 脚本语言,是Linux平台开发必备技能。大牛都要掌握一两门脚本语言的哦~ 
 
总结来说,我觉得大家都不需要太着急,不要纠结于,我到底应该学些什么,我什么时候才能变成一个牛人。以前我每天爬山背单词,也不知道自己的英语究竟在什么水平了,但有一天碰到一个老外,才知道自己的英语原来已经这么溜了!所以其实,当你在实践中,逐渐得学习了很多东西,当你回过头来看的时候,就会发现自己已经站在很高的地方了!  
最后借用人生的三个境界来分享我的学习心境: 
最开始是迷茫的:昨夜西风凋碧树。独上高楼,望尽天涯路。 然后找到了自己喜欢的东西:衣带渐宽终不悔,为伊消得人憔悴。 接着就可以找到一些喜悦:众里寻他千百度,蓦然回首,那人却在,灯火阑珊处。 
 
 谢谢! 
 
 下面是一些问答实录:
 
 1、对于非IT专业的在IT界发展有啥建议吗?
 
 首先找准职业方向,可能会走很多弯路,再找方向的阶段多听专业人的意见,找到适合自己的 ,然后沉下来学习即可。最重要的是好好提高编码能力,要从基础开始,从java基本语法开始,扎实基本功,IT是最不问出生的行业,无论是什么专业,只要有技术都能找到好工作。
 
 2、30岁后程序员转哪些职业? 
找到自己奋斗的方向,就不会觉得累也不会没有目标。找目标的过程很重要!我找到的就是大数据方向,对我来说为伊消得人憔悴,我不会转型,会朝这个方向一直努力。 
 
3、大数据应该学哪些东西?是不是对算法要求比较高? 
 
首先,优酷上找一些视频,如R语言的视频教程;然后学习公开课;《数据挖掘概念与技术》等机器学习方面的书;读机器学习方面的博客,一篇好的博客可以写一个算法。主要是借助网络来学习。《数学之美》把数学讲的很通俗,机器学习必看。 
 
 4、Java的基本功能书有推荐吗? 
《thinking in Java》。 JDK源代码,tomcat源代码,还是要多看源代码,面试的时候很有用。
 
 5、如何管理你的知识? 
技多不压身,不需要管理。 
 
6、追求技术的同时,怎么看待薪水和现实之间的矛盾?
 薪水和现实之间是没有矛盾的,前几年不要对薪水有太高的期望,够生活,够自己花就好了,三年后你奋斗成高级工程师后再想着攒钱买房这些事情,所以我认为只要好好学技术就好,不会有太大的矛盾。 收起阅读 »

环信推反垃圾服务,八大技术为用户保驾护航

那些年,用户被虚假广告塞的坛满钵满;那些年,网民被欺诈信息骗的倾家荡产;那些年,色情图片搞得社区难以正常发展;那些年,反动信息让平台面临关停的风险。据《中国网民权益保护调查报告(2015)》显示,2015年网民因个人信息泄露、垃圾信息、诈骗信息等现象,总体损失...
继续阅读 »
那些年,用户被虚假广告塞的坛满钵满;那些年,网民被欺诈信息骗的倾家荡产;那些年,色情图片搞得社区难以正常发展;那些年,反动信息让平台面临关停的风险。据《中国网民权益保护调查报告(2015)》显示,2015年网民因个人信息泄露、垃圾信息、诈骗信息等现象,总体损失高达805亿元。同时,垃圾信息也极大影响互联网产品用户体验,如果不加以控制,只能眼睁睁地看着活跃度下降用户不断流失。


16-15122111201L10.jpg


诈骗垃圾消息示例
 
 互联网企业因此面临着各方面巨大的压力,为此不得不投入大量的资源。大型互联网公司都有专门的反垃圾研发团队,人数动辄数人甚至数十人。但大多数中小型互联网创业公司资源有限,很难专门建立自己的反垃圾团队。在美国,已经有多家创业公司以云服务或其他形式提供反垃圾服务。而在中国,反垃圾市场缺口巨大,但目前还没有第三方的专业反垃圾服务提供商。


16-151221112029239.jpg


广告、色情垃圾消息示例
 
为了维护平台以及网民的合法权益不再遭受垃圾信息的侵害,作为全球最大的即时通讯云PaaS平台,环信率先推出了反垃圾服务
 
 
一,反垃圾服务“Anti-spam”面临六大挑战

反垃圾服务“Anti-spam”是一项长期并且艰巨的工作,面临以下六大挑战:
1)1:n,一个anti-spam团队要面临看不见的千千万万的spammer(人或者机器);
2)spammer利益丰厚,已经形成完整的地下黑色产业链;
3)spam的成本越来越低,打码网站(第三世界打码平台),万能的淘宝(IP代理库,手机黑卡,马甲账号)等;
4)spam质量越来越高,软文与正常用户的文章差异越来越少;
5)anti-spam是拉锯战,学术界和工业界多采用机器学习的方法进行,但只要产品有流量,spammer会坚持不懈地研究策略和规则来绕开设定的屏障。anti-spam与其说是machine learning,不如说是adversarial learning;
6)anti-spam在大多数公司都是一个黑盒,为了保护自己,核心技术很少会拿出来公开交流。


二,环信反垃圾“anti-spam”服务八大技术让垃圾消息无所遁形

    环信作为国内即时通讯云行业的开创者,有着连接人与人,连接人与商业的愿景。不仅致力于为用户提供高稳定高可靠的底层消息服务,更致力于帮助用户不断优化产品打造更好的用户体验,从而实现双赢。在反垃圾服务方面,环信anti-spam团队将通过以下技术力图识别恶意机器程序,将用户spam控制在可接受的范围内。


16-151221112110Z5.jpg


环信反垃圾服务架构图
 
1、关键词过滤系统,主要用来过滤非法政治言论以及部分色情信息;
2、基于行为分析的spammer识别系统,借助互联网用户行为的特征进行spammer识别;
3、恶意内容样本自学习系统。基于内容的spammer识别系统,通过训练,指针对用户的内容数据做判断,从语义的角度分析spam的类别;
4、实时策略部署,紧急帮助用户拦截临时爆发的spam;
5、用户产品指导等(注册马甲拦截,活动刷单等); 

    在上述anti-spam过程中,环信将会对用户的用户ID做匿名处理,充分保护用户隐私。并且将使用高效、准确的机器学习模型进行智能识别。

    未来,环信还将部署以下三大技术: 1、消息恶意代码检测,xss等潜在的恶意攻击;2、恶意URL检测,钓鱼网站等虚假URL检测; 3、语音,图片,视频等spammer智能识别系统;


三,环信反垃圾“anti-spam”增值服务流程简介:

1、环信反垃圾服务属于增值服务,将面向所有互联网企业,同时将优先向环信即时通讯云和环信移动客服老用户开放。
2、企业可以联系环信商务申请开通反垃圾服务。
3、环信反垃圾团队将跟企业沟通,了解用户垃圾消息的定义,商定垃圾消息的处理流程。
4、对企业的数据匿名处理,训练模型,上线服务。
5、环信将不断改进模型,提高准确率和召回率,同时帮助企业应对临时事件。

    截至12月份,已经有数十家环信老用户试用开通了环信反垃圾服务。某知名女性社交App在申请试用环信反垃圾服务以后,环信选择其数据使用环信行为识别系统进行识别,发现该App目前的垃圾消息占比高达40%,其中,垃圾消息主要分为非法广告和虚假兼职两类,比例为9:1,极度影响用户体验。

    通过环信行为检测系统,垃圾消息监测准确率高达99%,垃圾消息召回率高达82%。该社交产品负责人表示:“环信反垃圾服务上线后用户活跃度获得了明显提升,以后再也不用为各种色情、政治类消息提心吊胆了。”

    环信反垃圾服务将于近期正式对外开放申请,具体请联系环信商务或者关注环信官网(http://www.easemob.com/)更新。

    名词解释:召回率,是机器学习的评判指标之一。举个例子,现在某App有1000条消息,其中300条是垃圾消息,通过系统识别出了240条我们“算法认定”的垃圾消息,经过人工鉴定,这240条垃圾消息就是样本中的垃圾消息,那么算法的召回率是240/300=80%,算法准确率是100%。因为算法是一个学习的过程,所以会漏掉一些垃圾消息用作学习成本。
  收起阅读 »

webim自动登录 多网页共存 输入框空消息判断

集成环信webim ,发现需要输入账号密码才能登陆,如果需要实现打开页面就直接登陆该怎么办? 以webdemo为例(demo下载地址http://www.easemob.com/downloads),打开index ,demo 的登陆是写了一个login...
继续阅读 »
集成环信webim ,发现需要输入账号密码才能登陆,如果需要实现打开页面就直接登陆该怎么办?

以webdemo为例(demo下载地址http://www.easemob.com/downloads),打开index ,demo 的登陆是写了一个login方法调用的conn.open。只需要在这个方法前写一个页面加载函数 ,直接调用login就可以实现我们需要的打开页面登陆功能
 

QQ截图20151221173013.png


就是这么酷炫,小伙伴们快去试一下吧!
 
接下来我们来看第二个问题,怎么实现多网页共存?还是老样子,先讲一下原理吧,
-conn.open的时候多传递参数,resource:随机值,每个tab中随机值不能一样,一样则会把前一个登录的踢出,默认都是webim
如果觉得看不懂也没关系,这个在环信webimsdk里已经写好了的,打开easemob.im-1.0.7.js 
把截图里圈出来的地方注释打开,下面resource_value注释掉(这下是不是明白了呢)


QQ截图20151221173151.png


 
 
在使用webdemo 的时候发现打开会话界面不输入消息,点击发送按钮(也就是发送一条空消息)这样会导致后续发不出去消息,这个应该怎么处理呢?
 
把这个判断注释掉即可


QQ截图20151221173324.png


 
上面说的三个技能都掌握了吗?附件为一份简单集成的demo,可以拿去参考下。

有关于环信集成问题或者想了解哪方面移动互联网知识,可以在下方评论留言,我们就计划更新出来。
  收起阅读 »

关于视频聊天的问题

我在集成了EaseUI3.0后,发现对于视频聊天的请求,如果用户选择了不给权限,那么虽然应用会提示我们去隐私-》相机然后后找到相应的应用打开权限,但我测试发现在列表中并没有列出来我们的app。经过查找,感觉问题在CallViewController.m的can...
继续阅读 »
我在集成了EaseUI3.0后,发现对于视频聊天的请求,如果用户选择了不给权限,那么虽然应用会提示我们去隐私-》相机然后后找到相应的应用打开权限,但我测试发现在列表中并没有列出来我们的app。经过查找,感觉问题在CallViewController.m的canVideo方法。这里对能否访问摄像头进行了判断,但没有尝试去获取权限。因此我将代码修改为如下内容。完美解决这个问题。
+ (BOOL)canVideo
{
if([[[UIDevice currentDevice] systemVersion] compare:@"7.0"] != NSOrderedAscending){
// if(!([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] == AVAuthorizationStatusAuthorized)){\
// UIAlertView * alt = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"setting.cameraNoAuthority", @"No camera permissions") message:NSLocalizedString(@"setting.cameraAuthority", @"Please open in \"Setting\"-\"Privacy\"-\"Camera\".") delegate:self cancelButtonTitle:nil otherButtonTitles:NSLocalizedString(@"ok", @"OK"), nil];
// [alt show];
// return NO;
// }
NSString *mediaType = AVMediaTypeVideo;// Or AVMediaTypeAudio
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType];
NSLog(@"---cui--authStatus--------%d",authStatus);
// This status is normally not visible—the AVCaptureDevice class methods for discovering devices do not return devices the user is restricted from accessing.
if(authStatus ==AVAuthorizationStatusRestricted){
NSLog(@"Restricted");
}else if(authStatus == AVAuthorizationStatusDenied){
// The user has explicitly denied permission for media capture.
NSLog(@"Denied"); //应该是这个,如果不允许的话
UIAlertView * alt = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"setting.cameraNoAuthority", @"No camera permissions") message:NSLocalizedString(@"setting.cameraAuthority", @"Please open in \"Setting\"-\"Privacy\"-\"Camera\".") delegate:self cancelButtonTitle:nil otherButtonTitles:NSLocalizedString(@"ok", @"OK"), nil];
[alt show];
return NO;
}
else if(authStatus == AVAuthorizationStatusAuthorized){//允许访问
// The user has explicitly granted permission for media capture, or explicit user permission is not necessary for the media type in question.
NSLog(@"Authorized");

}else if(authStatus == AVAuthorizationStatusNotDetermined){
// Explicit user permission is required for media capture, but the user has not yet granted or denied such permission.
[AVCaptureDevice requestAccessForMediaType:mediaType completionHandler:^(BOOL granted) {
if(granted){//点击允许访问时调用
//用户明确许可与否,媒体需要捕获,但用户尚未授予或拒绝许可。
NSLog(@"Granted access to %@", mediaType);
}
else {
NSLog(@"Not granted access to %@", mediaType);
}

}];
}else {
NSLog(@"Unknown authorization status");
}
}

return YES;
}
收起阅读 »

集成笔记:环信移动客服如何实现全媒体接入

本篇集成笔记参考于环信官网移动客服集成文档 ,写这篇笔记是为了让大家更直观的了解“移动客服是什么”“我能不能使用移动客服”“怎么集成移动客服” 官网移动客服集成文档地址:http://docs.easemob.com/cs/start 移动客服是由环信提供...
继续阅读 »
本篇集成笔记参考于环信官网移动客服集成文档 ,写这篇笔记是为了让大家更直观的了解“移动客服是什么”“我能不能使用移动客服”“怎么集成移动客服”

官网移动客服集成文档地址:http://docs.easemob.com/cs/start

移动客服是由环信提供的一套完整的客服服务SaaS解决方案,既包括多渠道接入的客户端(APP,网页,微信,微博),也包括客服座席使用的服务端(Web和APP都有),只是在APP端使用了IM作为通讯方式。
访客端是由自己集成(集成步骤在下面文档会写出),目前支持:APP、微信公众号、微博公众号、网站
客服后台是由环信提供,现支持:移动端、web、pc端(插件方会在以后版本开放,具体可咨询环信在线技术支持)


QQ截图20151221160139.png


集成环信移动客服前需注册环信客服账号,并登录。......
环信客服注册地址:http://kefu.easemob.com/mo/register


网页插件集成:
网页插件集成移动客服是比较简单,原理是在自己网站的标签之前加入一段由环信提供的js,即可完成环信在线客服的植入,实现访客在网页端与在线客服的沟通。

QQ截图20151221160416.png


这段js获取步骤如下:
管理员模式下==》渠道设置==》网页插件

QQ截图20151221160522.png


下面来讲下网页插件的功能介绍和自定义开发(V4.1版本)
功能介绍可参考imgeek社区新产品发布:http://community.easemob.com/article/825307446 

一些常见的自定义开发
Q:网页插件 集成自定义按钮
A:首先,将插件JS串中的hide=false修改为hide=true;
其次,在你网页的目标元素上添加如下超链接,例如:你的目标元素,即可完成自定义客服按钮
Q:网页插件区分技能组
A:http://kefu.easemob.com/webim/im.html?tenantId=xxxx&emgroup=技能组名称
注意:技能组名称外面没有单引号


手机APP集成:
手机APP集成可分为以下两步
1:先在客服后台创建一个关联
管理员模式下==》渠道设置==》手机APP 右上角添加环信关联
关联名称由自己定义,AppKey,ClientId,ClientSecret可以再环信开发者后台拿到(注册环信开发者账号https://console.easemob.com/index_register.html  注册完成创建应用--查看应用概况即可得到)
这里详细介绍下im服务号,im服务号为自己应用下的一个im账号(不用为每个用户创建,根据自己业务逻辑指定一个或者多个)
2:客户端写个联系客服按钮,点击联系客服,调用发消息方法,接收对象为客服后台创建的关联的im服务号,消息就会到客服后台,根据分配策略分配给对应的客服(V4.1版本 客服坐席分配策略为:max(客服坐席可接待人数-客服坐席已接待人数), 也就是说,新来会话会分配给理论最闲的那个客服坐席)

一些常见的自定义开发:
指定客服、技能组、满意度调查、显示用户信息可参考(原理为联系客服时通过传入扩展属性键值对,由客服后台解析辨别。键为环信实现约定好的,值是自定义。)文档地址:http://docs.easemob.com/cs/300visitoraccess/10nativeapp 


这里列举几个实现用户信息常遇到的问题
Q:已经按照文档传入用户信息,为什么客服后台还是没有看到用户信息
A:客服关闭会话,再次联系客服就行,已经建立的会话目前没有刷新访客昵称
Q:之前传入用户信息在客服后台显示了,后来传入新的用户信息为什么客服后台没有更新
A:已经在客服后台显示的用户信息不会随着扩展属性的更新而更新,目前的设计是访客第一次进入时展示信息给客服辨别,后续由客服手动备注
PS:如果自己APP 是基于h5开发的,或者不想集成环信im怎么使用环信的移动客服,可以参考之前的网页插件集成,将那段js中的tenantID填入以下网址中xxxx的位置:http://kefu.easemob.com/webim/im.html?tenantId=xxxx
在自己APP中点击联系客服跳转到这个H5会话窗口即可


微信公众号集成:
微信工作号集成需要注意的是个人的订阅号、测试公众号等,微信均没有开通客服接口的权限,所以粉丝收不到客服消息。
微信公众号集成分以下几类:
1:直接授权(通过在客服后台管理员模式==》渠道设置==》微信公众号 添加微信公众号即可)
需要注意的是授权以后自己之前对微信公众号所做的开发都不能使用,微信用户通过微信的输入框直接联系客服后台移动客服
2:通过定义菜单栏点击联系客服

QQ截图20151221160626.png


可以在微信公众号定义菜单栏,点击跳转到环信指定的网址(这个地址可参考之前的网页插件集成,将那段js中的tenantID填入以下网址中xxxx的位置:http://kefu.easemob.com/webim/im.html?tenantId=xxxx )
3:回调集成(需要开发者,涉及到服务端程序的集成)
实现原理为环信发消息给微信,是通过环信的实时消息旁路接口。微信发消息给环信,是通过环信提供的REST发消息接口。
按照以下步骤:
1)在微信公众号开发者设置第三方服务器接收微信公众号的消息进行业务逻辑处理
2)调用环信rest接口将消息发给客服后台绑定的IM服务号(文档地址http://docs.easemob.com/doku.php?id=start:100serverintegration:50messages)
3)客服的回复消息是到环信服务器,通过回调接口把这消息转发到用户指定的服务器(需要符合环信格式,配置消息回调可联系环信在线技术支持)
4)服务器拿到消息之后在推给微信粉丝就行
PS:需要注意的是消息格式的变化(V4.1视频和位置暂不⽀持,会在下⼀版本提供⽀持)


微博公众号集成:
微博公众号集成目前支持私信、 @ ,评论暂不支持(V4.1版本)
集成方式:
管理员模式下==》渠道设置==》微博公众号


QQ截图20151221160725.png


 

  收起阅读 »

赞赏提现功能已经ready , 收到赞赏的同学可以申请提现了,真金白银,童叟无期

终于 ,我们可以愉快的打赏了。      
终于 ,我们可以愉快的打赏了。  


1.jpg




2.jpg


 
 

艾媒咨询(iiMedia Research ): 2015中国移动客服市场发展研究报告

话不多说,要下载的速度啦!


QQ截图20151216120731.jpg




QQ截图20151216120743.jpg




QQ截图20151216120759.jpg


话不多说,要下载的速度啦!

”活动“模块上线,大家有地儿活动啦

有没有同学注意到, imgeek“活动”模块悄然上线啦, imgeek将定期组织线下技术活动,区别于众多的活动站,imgeek将遵循开源社区开放、自由、分享的精神,具有几个特点:   1.开放演讲申请,任何人都可以提交演讲 2.开放投票,你的投票将直接决定演讲...
继续阅读 »
有没有同学注意到, imgeek“活动”模块悄然上线啦, imgeek将定期组织线下技术活动,区别于众多的活动站,imgeek将遵循开源社区开放、自由、分享的精神,具有几个特点:
 
1.开放演讲申请,任何人都可以提交演讲
2.开放投票,你的投票将直接决定演讲顺序
3.开放赞助商申请,有钱出钱,没钱出礼品,同时imgeek给一些品牌露出的机会
4.开放志愿者申请,给虽然暂时不能登上讲坛,又热心参与活动的同学一些贡献的机会,每个志愿者都将得到一个精美纪念品
5.开放“向讲师提问”,你的提问同时将进入imgeek“问题”模块,不光讲师可以及时回复你的问题,更多的同学将会看到
6.如果你还没有imgeek社区账号,报名后将为你自动生成一个社区账号,省去频繁注册账号的麻烦
 
总之,活动是大家的,舞台是大家的,尽情参与吧!
 
最近的一期活动将在2016-01-09 13:30 举行, 大家记得报名哦
 
活动入口:点击顶部“活动”菜单 or http://www.imgeek.org/activity/
 
 
 
  收起阅读 »

登录,大概3秒多,感觉有点慢,能优化下吗

登录,大概3秒多,感觉有点慢,能优化下吗
登录,大概3秒多,感觉有点慢,能优化下吗

小众公众号的简单运营

我们从4月初开始运营一个新的公众号。目前一直在持续运营中,粉丝数量和粉丝关注度也保持稳步上升,每天分享的文章也有很多的好评,得到转发。同时也收到过很多的吐槽,但我们一直很关注粉丝的反馈和吐槽,毕竟这才能让我们做的更好。 但是公众号运营的痛点太多了。粉丝增...
继续阅读 »
我们从4月初开始运营一个新的公众号。目前一直在持续运营中,粉丝数量和粉丝关注度也保持稳步上升,每天分享的文章也有很多的好评,得到转发。同时也收到过很多的吐槽,但我们一直很关注粉丝的反馈和吐槽,毕竟这才能让我们做的更好。

但是公众号运营的痛点太多了。粉丝增长不够快,用户粘性不够大,文章阅读数量不够多,传播力度不够广。对于一个公众号来说,不论粉丝多还是少,热情还是不热情,都需要运营人员精心的照料。今天我不说怎么推广这个公众号,只从自己经营这个公众号以来得到的一点经验来分项怎么做一个公众号。
 

  • 公众号建设

  • 首先公众号要有一个自己的形态,现在分订阅号、服务号、企业号三种,最常见的,也是我正在做的就是订阅号,我的号也是提供了公众号最基础的服务,信息推送。



  • 1.不可忽视的自动回复内容:



  • 自动回复有下面几种情况:被添加的内容、自动回复内容、特定关键词回复内容






  • 被添加的自动回复是一个用户对你的公众号的第一次接触,如果写的过长或者过短都会影响用户对公众号的认知。如果是“你好,欢迎关注***”,那么用户只会觉得,你没有用心在经营这个号,如果长篇大论得说你的产品特色,也容易让人厌倦。所以建议是,先打招呼,再简单一句话介绍公众号的功能。






  • 自动回复,根据微信公众号的规则,在1小时内自动回复只会被出发一次,所以这块建议就是写上,已收到,会尽快回复之类的字眼就可以。






  • 关键词自动回复,这块就比较灵活。我的公众号在做信息查询的时候会常用到这个。一般也不需要设置关键词回复。特别的可以提示的是,比方说有活动这类的内容,那么关键词可以设置一个“活动”,方便用户找到想要的信息。






  • 2.让信息更有条理的菜单栏设置


 

  • 很多小微公众号会忽视菜单栏的设置,但是其实菜单栏是必不可少的。公众号的特点是每天只能建立一条群发,这就容易导致,万一添加的用户是在你群发之后,或者今天用户不巧没有收到你的信息(这个情况还是很少见),那就会造成进入后,没有直接沟通交流的机会,很尴尬,所以如果你的公众号设置一个简单的菜单,让新用户,或者是想了解更多的用户有查看的平台。






菜单栏的作用.png


  • 每日推送内容

  • 每日推送也是公众号最重要的内容。我们的公众号是做IT资讯推荐的,所以,我们每天有基本的模式。






  • 如果文章分2、1,其中2为引流文章,让用户看了愿意分享的,1为增强用户知识体系,看了愿意不停关注来提升自己的能力。选文章的前提是精和新。



  • 每天的基本模式:精选2+技术干货1+大数据1+互联网金融1+o2o1+电商1+产品经理1






  • 其实在固定模式下推送新闻,不用多久就能发现用户比较关注的焦点。而且推送内容的走向也和时间有一定联系。由一周的统计可以看出秋季招聘期间面试经验、干货内容是比较受关注的,双十一期间电商和创业的关注度也比较高。



  • 169  【面试经验】腾讯、百度、网易游戏、华为Offer及笔经面经



  • 151  【技术干货】Google开源最新机器学习系统TensorFlow



  • 146  【面试经验】产品经理面经:3个产品Offer是如何拿到的



  • 153  【面试经验】零产品经验斩获校招产品Offer经历



  • 146  【面试经验】给Android程序员的一些面试建议



  • 190  【技术干货】分类算法总结



  • 153  【创业】2015年的互联网创业趋势可能不是你想象的那么回事



  • 147  【电商】双11这天,90%程序员都在干什么?



  • 143  【产品】别老想着脱单,今年流行“性冷淡”产品



  • 145  【创业】曾穷到被女友抛弃的他投奔马云后身价102亿



  • 177  【创业】那家将融10亿美元的AR公司Magic Leap到底有多拽



  • 162  【社会】人与人之间变得更冷漠,和手机一毛关系都没有



  • 以上是根据一周的统计内容得到最关注的焦点

  • 内容编辑

  • 标题:无所谓标题党,但标题请简洁。太长的标题,在碎片化信息时代,容易令人厌倦。



  • 摘要:你可能会觉得摘要没有用,编辑内容的时候我们总是会忽视摘要的部分,而在转发的时候摘要是必须会出现的,这时候如果摘要不编辑好,内容就会很乱,也影响转发的效果。转发的时候也别空转发,稍微写点内容,自己的看法,会更吸引其他用户的注意。







让转发更好看.png

     摘要写好了:


摘要写好了.png

     摘要没写好:


摘要没写好.png


  • 文字:分段,分段,分段!文字必须分段,不分段的手机效果就是挤在一起,令人不想看。字号的大小,新闻类的文章建议16px,这样看起来最舒服;文艺小清新类的文章建议14px,文艺范儿的小一点反而轻巧。



  • 图片:文章最好能够图文并茂,图片居中看起来会舒服很多。



  • 段落:用编辑器加一些看起来更简洁的小图标,对整篇文章的帮助是很大的。






分段小图标.png





  • 找对人群

  • 公众号相当于一个产品,所以找准定位对于找对一群适合的人群很重要。对的人群指的应该不是一次突然骤增的人数,而是长期用户的保留。




做一次校园IT推广的强度.png

     我们找准定位为正在找工作的大学生之后在做推广,效果就出现了非常显著的高峰。

  • 最重要的小事

  • 推送时间:



  • 推送时间真的非常重要,甚至是一篇相同的文章,不同的时间推送,阅读量和转发量也会大不相同。之前一直在探索最佳的推送时间,得到一个基本觉得很靠谱的结论。



  • 最忌:中午推送



  • 一般:早晨



  • 最佳:晚上8点-9点之间


收起阅读 »