最近的生活
上一篇文章是8.4号写的,一个多月没有写东西了,按照现在的情况估计,年底要写到40篇有点悬,虽然有很多要写的,但现在事情太多了也太累了。今天写点随笔,写到哪算哪吧。
工作
这次参与的新项目,前景还是不错的,不过活也是真多。这段日子,很多时候十一二点才下班,有的时候搞到两点,周末再加一天班。
业务快速发展,不断地有新同学加入,架构也在不断迭代,其实感觉还是蛮不错的,有点像当初刚工作负责电商的时候了,始终创业啊。
雷总曾经说过,要顺势而为,其实是对的,选对方向往往事半功倍,但选对方向需要极强的能力。新的变革已经到来了。
文化
这里的文化是指公司文化,扩展一下也指家庭文化。为什么突然聊文化?
最近感觉无论是家庭还是公司,让大家聚集在一起努力的,相同的文化或者三观是重要的一环。文化认同不一致,很难长久的在一起,这个没有对错,每个人都有选择的权利,没必要强求,很多时候祝福就好。
还是想夸一下字节的文化,虽然看过很多公司的文化宣言,感觉字节的带着哲思在里面,这种文化不是只对公司有利,而是说在自己的生活中,用这种文化来要求自己也是好的。认同这种文化的人在一起,办事效率、质量要高很多,很多时候,损失来自于内耗。
1.1追求极致
不断提高要求,延迟满足感
在更大范围里找最优解
不放过问题,思考本质
持续学习和成长
1.2务实敢为
直接体验,深入事实
不自嗨,注重效果
能突破有担当,打破定式
尝试多种可能,快速迭代
1.3开放谦逊
内心阳光,信任伙伴
乐于助人和求助,合作成大事
格局大,上个台阶想问题
对外敏锐谦虚,ego(自我) 小,听得进意见
1.4坦诚清晰
敢当面表达真实想法
能承认错误,不装不爱面子
实事求是,暴露问题,反对“向上管理”
准确、简洁、直接,有条理有重点
1.5始终创业
自驱,不设边界,不怕麻烦
有韧性,直面现实并改变它
拥抱变化,对不确定性保持乐观
始终像公司创业第一天那样思考
1.6多元兼容
理解并重视差异和多元,建立火星视角
打造多元化的团队,欢迎不同背景的人才,激发潜力
鼓励人人参与,集思广益,主动用不同的想法来挑战自己
创造海纳百川,兼容友好的工作环境
教育
最近在想,怎么教育好下一代?或者话题小一点,如何在知道A选项不好的情况下,让子女听自己的?
以前看过一篇文章,说是孩子们总归不会听你的,但他们也终会在跌跌撞撞中长大,然后他们的子女再来一次循环。
但我觉得,还是有可能教育好的,不过要付出很多,这是一个细雨润无声,充斥在点点滴滴生活中的事情,它永远不是一个一次性任务,或者说几次道理就能达成的。
拿选择来说,需要做到
父母本身就对每种选择的结果比较知晓
父母很了解子女的性格和能力
子女相对相信父母
或者 子女已经培养的很好了,有了自己的主见和三观,知道自己的性格和能力
如果能培养到第四点,那真是轻松很多。不过呀,最重要的还是得立志,论语里说:“不愤不启,不悱不发,举一隅不以三隅反,则不复也。”也是这个道理。立志能给人以动力,自己主观上想干了,才能干好。
家庭
最近媳妇工作上的事情也比较多,我感觉很神奇,好像每次事情都会像商量好似得一起来,这时候考验的就是毅力和耐力,不松气,努力干,总能顶过这一波。
或许真像媳妇说的,人生就像一场游戏,努力就完事了,别想太多。
前些日子和媳妇都阳了,好在不太严重,也不知道什么时候是个头。看到满满的小药箱,比起去年12月的时候,还是感觉安全一些的。
哦,对了,前些日子公司冷藏柜漏水,导致我摔了一跤,电脑都飞出去了。怎么说呢,幸亏电脑没事,就人伤着一点,哈哈哈。本来想投诉一下,但负责人一直在会议室门口等我们会议结束,又道歉又拿药,加了联系方式方便后面有问题及时联系;同时讲了原因和后续的改进措施。做的挺不错的。
以前对摔倒的影响概念不深,现在倒蛮有体会的了,有时候在想,如果六七十岁的人,以这个力道被摔,真的很危险。大家还是要多多注意。
链接:https://juejin.cn/post/7276368438145859603
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
职场坐冷板凳的那些日子
曾经有一段职场生涯,坐了很长时间的冷板凳,也正是那段经历,彻底改变了整个职场生涯。今天这篇文章聊聊自己曾经的经历,也聊聊如果在职场中被坐了冷板凳该咋办。
关于冷板凳
有人的地方就有江湖。而这个江湖中是否性情相同,是否因某些事(或利益)产生矛盾,都可能造成职场坐冷板凳的情况。
冷板凳常见于上级对下级的打压。一般手段就是让你无所事事或安排一些边缘性的事务,不怎么搭理你,从团队层面排挤你,甚至否定你或PUA你,别人也不敢跟你沟通,以至于让你在团队中形成孤立的的状态。
根据矛盾或冲突的不同,冷板凳的程度也不同。常见的有:浅层次的冲突,可进行修复;不可调和,无法修复;中间的灰度状态。
通常根据具体情况,判断程度,有没有可能或必要修复,再决定下一步的行动。
第一,可修复的冷板凳
有很多同学,特别是技术人,在职场上有时候特别的“刚”,为了某个技术点跟领导争的面红耳赤的,导致被坐冷板凳。
比如有同学曾有这样的经历:领导已经拍板的决定,他很刚的去跟领导据理力争,导致起了冲突,大吵一架,领导也下不来台。随后领导好几天没搭理他。
针对这种情况,一般也就是一顿火锅的事,找领导主动沟通,重拾信任。甚至可能会出现不打不相识的情况。当然,一顿火锅不够还可以两顿。
第二,清场性质的冷板凳
这种情况常见于业绩或能力不达标,已经是深层次的矛盾,一般会空降过来一个领导,故意将其边缘化。属于清场接替工作性质的,基本上无法修复。
针对这种情况,看清局势,准备好找下家就是了。如果做得好,准备好交接工作,给彼此一个体面。毕竟,很多事情我们是无法改变的。
第三,灰度状态的冷板凳
以上两个常见都比较极端,而大多数情况下都是灰度状态的,大的可能性就是一直僵持着。这时作为下属的人,一般建议主动去沟通、修复。
如果阅历比较浅,看不出中间的微妙关系以及深层次的冲突点,就请人帮你看看,听听别人的建议和决策。再决定值不值得修复,要不要修复。
我的冷板凳
曾经我在一家公司坐的冷板凳属于第三种,但却把这个冷板凳坐到了极致。下面就讲讲我曾经的故事。
跟着一个领导到一家新公司,本来领导带领技术部门的,但由于内部斗争的失利,去带产品团队了,而我也归属到他对手的手下了。这种情况下,冷板凳是坐定了,但也不至于走人。
被新领导安排了一个很边缘的业务:对接和维护一套三方的系统。基本上处于不管不问,开会不带,接触不到核心,也与其他人无交流的状态。起初这种状态非常难受,人毕竟是社群动物,需要一个归属感和存在感的。
但慢慢的,自己找到了一些属于自己的乐趣。
首先,没人管没人问,那就可以自己掌控节奏和状态了。看他们天天加班到凌晨一两点,而自己没人管,六七点就下班了。最起码在那段持续疯狂加班的岁月里,自己保住了头发。那位大领导后来加班太多,得了重病,最终位置也没保住。
其次,有了大把的时间。上班几乎没人安排工作,于是上班的时间完全自己安排。三方服务商安排了对接人,好歹自己作为甲方,于是天天就跟服务商的技术沟通,询问他们系统的设计实现,技术栈什么的。
在那段岁月里,完成了几个改变后续职场生涯的事项。
事项一:那时Spring Boot 1.5刚刚发布,公司的技术栈还没用上,但服务商的这套系统已经用上了。感觉这玩意太好用了,于是疯狂的学学习。因为当初的学习,后来出版了书籍《Spring Boot技术内幕》那本书。
事项二:写技术博客,翻译技术文档,录技术视频。服务商的系统中还用到了规则引擎,当时市面上没有相关的中文资料。于是边跟对方技术沟通,边翻译英文文档,写博客。后来,还把整理的文档录制成视频,视频收入有几万块吧。
这算是自己第一次尝试翻译文档、录制教学视频,而且这个领域网络上后续的很多技术文章都是基于我当初写文章衍生出来的。最近,写的第二本书便是关于规则引擎的,坐等出版了。
事项三:学习新技术,博客输出。当时区块链正火爆时。由于有大量的时间,于是就研究起来了,边研究边写技术博客。也是在这个阶段,养成了写技术博客的习惯。
因为区块链的博客,也找到了下家工作。同时写了CSDN当时类似极客时间的“Chat”专栏,而且是首批作者。也尝试搞了区块链的知识星球。后来,因为区块链的工作,做了第一次公开课的分享。还是因为区块链相关,与别人合著了一本书,解释了出版社的老师,这也是走上出书之路的开始。
因为这次冷板凳,让职场生涯变得极其丰富,也扭转了大的方向,发展了副业,接触了不同行业领域的人。
最后的小结
在职场混,遇到坐冷板凳的情况不可避免,但如何化解,如何抉择却是一个大学问。尽量主动沟通,毕竟找工作并不容易,也不能保证下家会更好。同时,解决问题,也是人生成长的一部分,所以,尽量尝试化解。
但如果矛盾真的不可调和或持续僵持,那么就更好做好决策,选择对自己最有利的一面。
曾在朋友圈发过这样一段话,拿来与大家分享:
“始终难守樊登讲过的一句话:人生成长最有效的方法,就是无论命运把你抛在任何一个点上,你就地展开做力所能及的事情。
如果还要加上一句,那就是:还要占领制高点。与君共勉~”
链接:https://juejin.cn/post/7267107420655583292
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
UIButton 扩大点击区域
在开发过程中经常会遇到设计给出的button尺寸偏小的情况.这种UIButton在使用中会非常难点击,极大降低了用户体验
解决方案一:重写UIButton的- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event方法
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event
{
//获取当前button的实际大小
CGRect bounds = self.bounds;
//若原热区小于44x44,则放大热区,否则保持原大小不变
CGFloat widthDelta = MAX(44.0 - bounds.size.width, 0);
CGFloat heightDelta = MAX(44.0 - bounds.size.height, 0);
//扩大bounds
bounds = CGRectInset(bounds, -0.5 * widthDelta, -0.5 * heightDelta);
//如果点击的点 在 新的bounds里,就返回YES
return CGRectContainsPoint(bounds, point);
}
系统默认写法是:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
return CGRectContainsPoint(self.bounds, point);
}
其实是在判断的时候对响应区域的bounds进行了修改.CGRectInset(view, 10, 20)方法表示对rect大小进行修改
解决方案二 runtime关联对象来改变范围,- (UIView) hitTest:(CGPoint) point withEvent:(UIEvent) event里用新设定的 Rect 来当着点击范围。
#import "UIButton+EnlargeTouchArea.h"
#import <objc/runtime.h>
@implementation UIButton (EnlargeTouchArea)
static char topNameKey;
static char rightNameKey;
static char bottomNameKey;
static char leftNameKey;
- (void)setEnlargeEdgeWithTop:(CGFloat)top right:(CGFloat)right bottom:(CGFloat)bottom left:(CGFloat)left
{
objc_setAssociatedObject(self, &topNameKey, [NSNumber numberWithFloat:top], OBJC_ASSOCIATION_COPY_NONATOMIC);
objc_setAssociatedObject(self, &rightNameKey, [NSNumber numberWithFloat:right], OBJC_ASSOCIATION_COPY_NONATOMIC);
objc_setAssociatedObject(self, &bottomNameKey, [NSNumber numberWithFloat:bottom], OBJC_ASSOCIATION_COPY_NONATOMIC);
objc_setAssociatedObject(self, &leftNameKey, [NSNumber numberWithFloat:left], OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (void)setTouchAreaToSize:(CGSize)size
{
CGFloat top = 0, right = 0, bottom = 0, left = 0;
if (size.width > self.frame.size.width) {
left = right = (size.width - self.frame.size.width) / 2;
}
if (size.height > self.frame.size.height) {
top = bottom = (size.height - self.frame.size.height) / 2;
}
[self setEnlargeEdgeWithTop:top right:right bottom:bottom left:left];
}
- (CGRect)enlargedRect
{
NSNumber *topEdge = objc_getAssociatedObject(self, &topNameKey);
NSNumber *rightEdge = objc_getAssociatedObject(self, &rightNameKey);
NSNumber *bottomEdge = objc_getAssociatedObject(self, &bottomNameKey);
NSNumber *leftEdge = objc_getAssociatedObject(self, &leftNameKey);
if (topEdge && rightEdge && bottomEdge && leftEdge)
{
return CGRectMake(self.bounds.origin.x - leftEdge.floatValue,
self.bounds.origin.y - topEdge.floatValue,
self.bounds.size.width + leftEdge.floatValue + rightEdge.floatValue,
self.bounds.size.height + topEdge.floatValue + bottomEdge.floatValue);
}
else
{
return self.bounds;
}
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
CGRect rect = [self enlargedRect];
if (CGRectEqualToRect(rect, self.bounds) || self.hidden)
{
return [super hitTest:point withEvent:event];
}
return CGRectContainsPoint(rect, point) ? self : nil;
}
@end
解决方案三:使用runtime swizzle交换IMP
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSError *error = nil;
[self hg_swizzleMethod:@selector(pointInside:withEvent:) withMethod:@selector(hitTest_pointInside:withEvent:) error:&error];
NSAssert(!error, @"UIView+HitTest.h swizzling failed: error = %@", error);
});
}
- (BOOL)hitTest_pointInside:(CGPoint)point withEvent:(UIEvent *)event {
if (UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero)) {
return [self hitTest_pointInside:point withEvent:event];
}
CGRect relativeFrame = self.bounds;
CGRect hitFrame = UIEdgeInsetsInsetRect(relativeFrame, self.hitTestEdgeInsets);
return CGRectContainsPoint(hitFrame, point);
}
category的诞生只是为了让开发者更加方便的去拓展一个类,它的初衷并不是让你去改变一个类。
技术点总结
关联对象,也就是绑定对象,可以绑定任何东西
//关联对象
objc_setAssociatedObject(self, &topNameKey, [NSNumber numberWithFloat:top], OBJC_ASSOCIATION_COPY_NONATOMIC);
// self 关联的类,
//key:要保证全局唯一,key与关联的对象是一一对应关系。必须全局唯一
//value:要关联类的对象。
//policy:关联策略。有五种关联策略。
//OBJC_ASSOCIATION_ASSIGN 等价于 @property(assign)。
//OBJC_ASSOCIATION_RETAIN_NONATOMIC等价于 @property(strong, //nonatomic)。
//OBJC_ASSOCIATION_COPY_NONATOMIC等价于@property(copy, nonatomic)。
//OBJC_ASSOCIATION_RETAIN等价于@property(strong,atomic)。
//OBJC_ASSOCIATION_COPY等价于@property(copy, atomic)。
NSNumber *topEdge = objc_getAssociatedObject(self, &topNameKey);
// 方法说明
objc_setAssociatedObject 相当于 setValue:forKey 进行关联value对象
objc_getAssociatedObject 用来读取对象
objc_AssociationPolicy 属性 是设定该value在object内的属性,即 assgin, (retain,nonatomic)...等
objc_removeAssociatedObjects 函数来移除一个关联对象,或者使用objc_setAssociatedObject函数将key指定的关联对象设置为nil。
方法交换 Method Swizzling 注意点
对于已经存在的类,我们通常会在+load方法,或者无法获取到类文件,我们创建一个分类,也通过其+load方法进行加载swizzling
- Swizzling应该总在+load中执行
- Swizzling应该总是在dispatch_once中执行
- Swizzling在+load中执行时,不要调用[super load]。如果多次调用了[super load],可能会出现“Swizzle无效”的假象。
交换实例方法
以class为类
void class_swizzleInstanceMethod(Class class, SEL originalSEL, SEL replacementSEL)
{
//class_getInstanceMethod(),如果子类没有实现相应的方法,则会返回父类的方法。
Method originMethod = class_getInstanceMethod(class, originalSEL);
Method replaceMethod = class_getInstanceMethod(class, replacementSEL);
//class_addMethod() 判断originalSEL是否在子类中实现,如果只是继承了父类的方法,没有重写,那么直接调用method_exchangeImplementations,则会交换父类中的方法和当前的实现方法。此时如果用父类调用originalSEL,因为方法已经与子类中调换,所以父类中找不到相应的实现,会抛出异常unrecognized selector.
//当class_addMethod() 返回YES时,说明子类未实现此方法(根据SEL判断),此时class_addMethod会添加(名字为originalSEL,实现为replaceMethod)的方法。此时在将replacementSEL的实现替换为originMethod的实现即可。
//当class_addMethod() 返回NO时,说明子类中有该实现方法,此时直接调用method_exchangeImplementations交换两个方法的实现即可。
//注:如果在子类中实现此方法了,即使只是单纯的调用super,一样算重写了父类的方法,所以class_addMethod() 会返回NO。
//可用BaseClass实验
if(class_addMethod(class, originalSEL, method_getImplementation(replaceMethod),method_getTypeEncoding(replaceMethod)))
{
class_replaceMethod(class,replacementSEL, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
}else {
method_exchangeImplementations(originMethod, replaceMethod);
}
}
这里存在的问题是继承时子类没有实现父类方法的问题:
基类A类 有方法 -(void)test
子类B类继承自基类A,但没有重写test方法,即其类[B class]中没有test这个实例方法
当我们交换子类B中的方法test,交换为testRelease方法(这必然会在子类B中写testRelease的实现),子类B中有没有test方法的实现时,就会将基类A的test方法与testRelease替换,当仅仅使用子类B时,不会有问题。
但当我们使用基类A的test方法时,由于test指向的IMP是原testRelease的IMP,而基类A中没有这个实现,因为我们是写在子类B中的。所以就出现了unrecognized selector
交换类方法
由于类方法存储在元类中,以实例方法存在,所以实质就是交换元类的实例方法
上面交换实例方法基础上,传入cls为元类即可。
获取的元类可以这样objc_getMetaClass("ClassName")或者object_getclass([NSObject class])
事件响应者链
如图所示,不再赘述
两个重要的方法
- (nullable UIView*)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;称为方法A
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;称为方法B
对view进行重写这两个方法后,点击屏幕后,首先响应的是方法A;
如果方法A中,我们没有调用父类([super hitTest:point withEvent:event];)的这个方法,那就根据这个方法A的返回view,作为响应事件的view。(当然返回nil,就是这个view不响应)
如果方法A中,我们调用了父类的方法([super hitTest:point withEvent:event];)那这个时候系统就要调用方法B;通过这个方法的返回值,来判断当前这个view能不能响应消息
如果方法B返回的是no,那就不用再去遍历它的子视图。方法A返回的view就是可以响应事件的view。
如果方法B返回的是YES,那就去遍历它的子视图。(就是上图我们描述的那样,找到合适的view返回,如果找不到,那就由方法A返回的view去响应这个事件。)
总结
返回一个view来响应事件 (如果不想影响系统的事件传递链,在这个方法内,最好调用父类的这个方法)
- (nullable UIView*)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event{
return [super hitTest:point withEvent:event];
}
返回的值可以用来判断是否继续遍历子视图(返回的根据是触摸的point是否在view的frame范围内)
- (BOOL)pointInside:(CGPoint)point withEvent:(nullableUIEvent *)event;
链接:https://juejin.cn/post/6943628003976937508
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
手把手教你集成环信ReactNative离线推送(下)
点此链接查看:手把手教你集成环信ReactNative离线推送(上)
三、从原生将device_token 传到RN 并且绑定
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("deviceToken",jsonObject.toString());
package com.awesomeproject;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.xiaomi.mipush.sdk.MiPushClient;
import org.json.JSONException;
import org.json.JSONObject;
public class PushModule extends ReactContextBaseJavaModule {
private ReactApplicationContext reactContext;
public PushModule(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
}
@Override
public String getName() {
return "PushModule";
}
/**
从RN界面里面调用该方法
**/
@ReactMethod
public void getDeviceToken(){
MainApplication.getReactPackage().mModule.sendDataToJS( MiPushClient.getRegId(MainApplication.getContext()));
}
public void sendDataToJS(String deviceToken){
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("deviceToken",deviceToken);
jsonObject.put("deviceName","2882303761517520571");
} catch (JSONException e) {
throw new RuntimeException(e);
}
this.reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("deviceToken",jsonObject.toString());
}
}
NativeModules.PushModule.getDeviceToken();
DeviceEventEmitter.addListener('deviceToken',(res)=>{
const goosid = JSON.parse(res);
deviceToken = goosid.deviceToken;
manufacturer = goosid.deviceName;
console.log('React Native界面,收到数据:',goosid);
ChatClient.getInstance().updatePushConfig(push);
// 导入依赖库
import React, { useEffect } from 'react';
import {
DeviceEventEmitter,
NativeModules,
SafeAreaView,
ScrollView,
StyleSheet,
Text,
TextInput,
View,
} from 'react-native';
import {
ChatClient,
ChatMessage,
ChatMessageChatType,
ChatOptions,
ChatPushConfig,
} from 'react-native-chat-sdk';
// 创建 app
const App = () => {
// 进行 app 设置
const title = 'ChatQuickstart';
var deviceToken='';
var manufacturer='';
NativeModules.PushModule.getDeviceToken();
DeviceEventEmitter.addListener('deviceToken',(res)=>{
const goosid = JSON.parse(res);
deviceToken = goosid.deviceToken;
manufacturer = goosid.deviceName;
console.log('React Native界面,收到数据:',goosid);
})
const [appKey, setAppKey] = React.useState('1137220225110285#demo');
const [username, setUsername] = React.useState('p9');
const [password, setPassword] = React.useState('1');
const [userId, setUserId] = React.useState('');
const [content, setContent] = React.useState('');
const [logText, setWarnText] = React.useState('Show log area');
// 输出 console log 文件
useEffect(() => {
logText.split('\n').forEach((value, index, array) => {
if (index === 0) {
console.log(value);
}
});
}, [logText]);
// 输出 UI log 文件
const rollLog = text => {
setWarnText(preLogText => {
let newLogText = text;
preLogText
.split('\n')
.filter((value, index, array) => {
if (index > 8) {
return false;
}
return true;
})
.forEach((value, index, array) => {
newLogText += '\n' + value;
});
return newLogText;
});
};
// 设置消息监听器。
const setMessageListener = () => {
let msgListener = {
onMessagesReceived(messages) {
for (let index = 0; index < messages.length; index++) {
rollLog('received msgId: ' + messages[index].msgId);
}
},
onCmdMessagesReceived: messages => {},
onMessagesRead: messages => {},
onGroupMessageRead: groupMessageAcks => {},
onMessagesDelivered: messages => {},
onMessagesRecalled: messages => {},
onConversationsUpdate: () => {},
onConversationRead: (from, to) => {},
};
ChatClient.getInstance().chatManager.removeAllMessageListener();
ChatClient.getInstance().chatManager.addMessageListener(msgListener);
};
// SDK 初始化。
// 调用任何接口之前,请先进行初始化。
const init = () => {
let option = new ChatOptions({
autoLogin: false,
appKey: appKey
});
ChatClient.getInstance().removeAllConnectionListener();
ChatClient.getInstance()
.init(option)
.then(() => {
rollLog('init success');
this.isInitialized = true;
let listener = {
onTokenWillExpire() {
rollLog('token expire.');
},
onTokenDidExpire() {
rollLog('token did expire');
},
onConnected() {
rollLog('login success.');
setMessageListener();
},
onDisconnected(errorCode) {
rollLog('login fail: ' + errorCode);
},
};
ChatClient.getInstance().addConnectionListener(listener);
})
.catch(error => {
rollLog(
'init fail: ' +
(error instanceof Object ? JSON.stringify(error) : error),
);
});
};
// 注册账号。
const registerAccount = () => {
if (this.isInitialized === false || this.isInitialized === undefined) {
rollLog('Perform initialization first.');
return;
}
rollLog('start register account ...');
ChatClient.getInstance()
.createAccount(username, password)
.then(response => {
rollLog(`register success: userName = ${username}, password = ******`);
})
.catch(error => {
rollLog('register fail: ' + JSON.stringify(error));
});
};
// 用环信即时通讯 IM 账号和密码登录。
const loginWithPassword = () => {
if (this.isInitialized === false || this.isInitialized === undefined) {
rollLog('Perform initialization first.');
return;
}
rollLog('start login ...');
ChatClient.getInstance()
.login(username, password)
.then(() => {
rollLog('login operation success.');
let push = new ChatPushConfig({
deviceId:manufacturer,
deviceToken:deviceToken,
});
console.log("--------------------------------------------");
console.log(manufacturer);
console.log(deviceToken);
console.log("--------------------------------------------");
ChatClient.getInstance().updatePushConfig(push);
})
.catch(reason => {
rollLog('login fail: ' + JSON.stringify(reason));
});
};
// 登出。
const logout = () => {
if (this.isInitialized === false || this.isInitialized === undefined) {
rollLog('Perform initialization first.');
return;
}
rollLog('start logout ...');
ChatClient.getInstance()
.logout()
.then(() => {
rollLog('logout success.');
})
.catch(reason => {
rollLog('logout fail:' + JSON.stringify(reason));
});
};
// 发送一条文本消息。
const sendmsg = () => {
if (this.isInitialized === false || this.isInitialized === undefined) {
rollLog('Perform initialization first.');
return;
}
let msg = ChatMessage.createTextMessage(
userId,
content,
ChatMessageChatType.PeerChat,
);
const callback = new (class {
onProgress(locaMsgId, progress) {
rollLog(`send message process: ${locaMsgId}, ${progress}`);
}
onError(locaMsgId, error) {
rollLog(`send message fail: ${locaMsgId}, ${JSON.stringify(error)}`);
}
onSuccess(message) {
rollLog('send message success: ' + message.localMsgId);
}
})();
rollLog('start send message ...');
ChatClient.getInstance()
.chatManager.sendMessage(msg, callback)
.then(() => {
rollLog('send message: ' + msg.localMsgId);
})
.catch(reason => {
rollLog('send fail: ' + JSON.stringify(reason));
});
};
// UI 组件渲染。
return (
<SafeAreaView>
<View style={styles.titleContainer}>
<Text style={styles.title}>{title}</Text>
</View>
<ScrollView>
<View style={styles.inputCon}>
<TextInput
multiline
style={styles.inputBox}
placeholder="Enter appkey"
onChangeText={text => setAppKey(text)}
value={appKey}
/>
</View>
<View style={styles.buttonCon}>
<Text style={styles.btn2} onPress={init}>
INIT SDK
</Text>
</View>
<View style={styles.inputCon}>
<TextInput
multiline
style={styles.inputBox}
placeholder="Enter username"
onChangeText={text => setUsername(text)}
value={username}
/>
</View>
<View style={styles.inputCon}>
<TextInput
multiline
style={styles.inputBox}
placeholder="Enter password"
onChangeText={text => setPassword(text)}
value={password}
/>
</View>
<View style={styles.buttonCon}>
<Text style={styles.eachBtn} onPress={registerAccount}>
SIGN UP
</Text>
<Text style={styles.eachBtn} onPress={loginWithPassword}>
SIGN IN
</Text>
<Text style={styles.eachBtn} onPress={logout}>
SIGN OUT
</Text>
</View>
<View style={styles.inputCon}>
<TextInput
multiline
style={styles.inputBox}
placeholder="Enter the username you want to send"
onChangeText={text => setUserId(text)}
value={userId}
/>
</View>
<View style={styles.inputCon}>
<TextInput
multiline
style={styles.inputBox}
placeholder="Enter content"
onChangeText={text => setContent(text)}
value={content}
/>
</View>
<View style={styles.buttonCon}>
<Text style={styles.btn2} onPress={sendmsg}>
SEND TEXT
</Text>
</View>
<View>
<Text style={styles.logText} multiline={true}>
{logText}
</Text>
</View>
<View>
<Text style={styles.logText}>{}</Text>
</View>
<View>
<Text style={styles.logText}>{}</Text>
</View>
</ScrollView>
</SafeAreaView>
);
};
// 设置 UI。
const styles = StyleSheet.create({
titleContainer: {
height: 60,
backgroundColor: '#6200ED',
},
title: {
lineHeight: 60,
paddingLeft: 15,
color: '#fff',
fontSize: 20,
fontWeight: '700',
},
inputCon: {
marginLeft: '5%',
width: '90%',
height: 60,
paddingBottom: 6,
borderBottomWidth: 1,
borderBottomColor: '#ccc',
},
inputBox: {
marginTop: 15,
width: '100%',
fontSize: 14,
fontWeight: 'bold',
},
buttonCon: {
marginLeft: '2%',
width: '96%',
flexDirection: 'row',
marginTop: 20,
height: 26,
justifyContent: 'space-around',
alignItems: 'center',
},
eachBtn: {
height: 40,
width: '28%',
lineHeight: 40,
textAlign: 'center',
color: '#fff',
fontSize: 16,
backgroundColor: '#6200ED',
borderRadius: 5,
},
btn2: {
height: 40,
width: '45%',
lineHeight: 40,
textAlign: 'center',
color: '#fff',
fontSize: 16,
backgroundColor: '#6200ED',
borderRadius: 5,
},
logText: {
padding: 10,
marginTop: 10,
color: '#ccc',
fontSize: 14,
lineHeight: 20,
},
});
export default App;
手把手教你集成环信ReactNative离线推送(上)
package com.awesomeproject;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.xiaomi.mipush.sdk.MiPushClient;
import org.json.JSONException;
import org.json.JSONObject;
public class PushModule extends ReactContextBaseJavaModule {
private ReactApplicationContext reactContext;
public PushModule(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
}
@Override
public String getName() {
return "PushModule";
}
/**
从RN界面里面调用该方法
**/
@ReactMethod
public void getDeviceToken(){
MainApplication.getReactPackage().mModule.sendDataToJS( MiPushClient.getRegId(MainApplication.getContext()));
}
public void sendDataToJS(String deviceToken){
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("deviceToken",deviceToken);
jsonObject.put("deviceName","");
} catch (JSONException e) {
throw new RuntimeException(e);
}
this.reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("deviceToken",jsonObject.toString());
}
}
package com.awesomeproject;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class PushPackage implements ReactPackage {
public PushModule mModule;
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> list = new ArrayList<>();
mModule = new PushModule(reactContext);
list.add(mModule);
return list;
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
package com.awesomeproject;
import android.app.Application;