IOS 直播时进入后台 重新进入前台图像卡住

IM即时通讯admin 回复了问题 • 2 人关注 • 1 个回复 • 14 次浏览 • 1 天前 • 来自相关话题

Flutter Platform Channel深度解析

IM即时通讯admin 发表了文章 • 0 个评论 • 107 次浏览 • 2021-01-28 14:20 • 来自相关话题

一、简介Platform Channel 是 Flutter 端与 Platform 端制定的通信机制,由官方提供用于 Dart 和平台之间的相互通信。分为以下 3 种(1)BaseMessageChannel :用于传递字符串和半结构化的信息(在大内存数据块... ...查看全部

一、简介

Platform Channel 是 Flutter 端与 Platform 端制定的通信机制,由官方提供用于 Dart 和平台之间的相互通信。

分为下 3 种

(1)BaseMessageChannel :用于传递字符串和半结构化的信息(在大内存数据块传递的情况下使用)

(2)MethodChannel:用于传递方法调用(Method Invocation

(3)EventChannel: 用于数据流(Event Streams)的通信

 

二、消息传递与编码器

Flutter 的消息传递工具是 BinaryMessager ,通过它与 Platform 建立起通信关系,消息以二进制的格式进行传递。

1.png

如图所示 BinaryMessager 的传递需要经过 BinaryMessageHandler,BinaryMessagerHandler 是以 Channel Name 作为键值生成出来再被注册到 BinaryMessager 上的,BinaryMessageHandler 和 BinaryMessager 是一一对应的,二进制格式的消息通过消息编码器(Codec)解码为识别的信息,并传递给 Handler 进行处理。Handler 处理完后,会把结果编码为二进制格式,再通过回调函数返回结果并发送回 Flutter 端

1.编码器分类

(1)MessageCodec:BinaryCodec、StringCodec、JSONMessageCodec、StandardMessageCodec

(2)MethodCodec:JSONMethodCodec、StandardMessageCodec

2.png

经过消息编码器处理后,消息就可以被 Handler 进行处理了

 

2.消息编码过程

Android 端的返回值是 java.lang.Integer 类型的,而 iOS 端返回值则是一个 NSNumber 类型的(通过NSNumber numberWithInt:获取)。而到了 Flutter 端时,这个返回值自动变成Dart 语言的 Int 类型。

standard platform channels 使用 standard messsage codec message response 进行序列化和反序列化,message response 可以是 booleans, numbers, Strings, byte buffers,List, Maps 等等,而序列化后得到的则是二进制格式的数据

Flutter 默认的消息编码器是 StandardMessageCodec ,支持的数据类型如下:3.png

三、MethodChannel

MethodChannel 是 Flutter 与 Platform之间传递信息的一种,其传递过程是:BinaryMessager > BinaryMessagerHandler > MethodChannel。

4.png

如上图:Native 端(iOS 和 Android)为宿主端(host)Flutter 则是客户端(client),Flutter 调用 Native 方法时,需要传递的信息是通过平台通道传递到宿主端的,Native 收到调用的信息后方可执行指定的操作。如有返回的数据,则 Native 会将数据再通过平台通道一并传递给 Flutter,其中数据传递是异步的,这样就能确保消息传递时用户界面不会被阻塞。

 

1.Flutter 层(Dart 层)

Flutter 端使用 MethodChannel 的 invokeMethod 方法发起一次方法调用时,开始了消息传递流程。 invokeMethod 方法会将其入参 message 和 arguments 封装成一个 MethodCall 对象,并使用 MethodCodec 将其编码为二进制格式数据,再通过 BinaryMessages 将消息发出。(注意,此处提到的类名与方法名均为 Dart 层的实现)

 上述过程最终会调用到 ui.Window 的 _sendPlatformMessage 方法,该方法是一个 Native 方法,其实现在 Native 层,这与 Java 的 JNI 技术非常类似。我们向 Native 层发送了三个参数:

            name,String 类型,代表 Channel 名称

            dataByteData 类型,即之前封装的二进制数据

            callback,Function 类型,用于结果回调

2.Native

Native 层后,window.cc 的 SendPlatformMessage 方法接受了来自 Dart 层的三个参数,并对它们做了一定的处理:Dart 层的回调 callback 封装为 Native 层的 PlatformMessageResponseDart 类型的 response;dart 层的二进制数据 data 转化为 std::vector<uint8t> 类型数据 data;根据 response, data 以及 Channel 名称 name 创建一个 PlatformMessage 对象,并通过 dartstate->window()->client()->HandlePlatformMessage 方法处理 PlatformMessage 对象。

dart_state->window()->client() 是一个 WindowClient,而其具体的实现为 RuntimeController,RuntimeController 会将消息交给其代理 RuntimeDelegate 处理。

RuntimeDelegate 的实现为 Engine,Engine 在处理 Message 时,会判断该消息是否是为了获取资源(channel 等于"flutter/assets"),如果是,则走获取资源逻辑,否则调用 Engine::Delegate 的 OnEngineHandlePlatformMessage 方法。

Engine::Delegate 的具体实现为 Shell,其 OnEngineHandlePlatformMessage 接收到消息后,会向 PlatformTaskRunner 添加一个 Task,该 Task 会调用 PlatformView 的 HandlePlatformMessage 方法。值得注意的是,Task 中的代码执行在 Platform Task Runner 中,而之前的代码均执行在 UI Task Runner 中。

四、消息处理

PlatformView 的 HandlePlatformMessage 方法在不同平台有不同的实现,但是其基本原理是相同的

5.png

1.PlatformView

AndroidPlatformViewAndroid 是 Platformview 的子类,也是其在 Android 端的具体实现。当 PlatformViewAndroid 接收到 PlatformMessage 类型的消息时,如果消息中有 response(类型为 PlatformMessageResponseDart),则生成一个自增长的 responseid,并以 responseid 为 key,response 为 value 存入字典 pendingresponses 中。接着,将 channel 和 data 均转化为 Java 可识别的数据,通过 JNI Java 层发起调用,将 response_id、channel 和 data 传递过去。

 Java 层中,被调用的代码为 FlutterNativeView (BinaryMessager 的具体实现)的 handlePlatformMessage ,该方法会根据 channel 找到对应的 BinaryMessageHandler 并将消息传递给它处理。

 BinaryMessageHandler 处理完成后,FlutterNativeView 会通过 JNI 调用 native 的方法,将 responsedata 和 responseid 传递到 native 层。

 Native 层,PlatformViewAndroid 的 InvokePlatformMessageResponseCallback 接收到了respondid 和 responsedata。其先将 responsedata 转化为二进制结果,并根据 responseid,从 pandingresponses 中找到对应的 PlatformMessageResponseDart 对象,调用其 Complete 方法将二进制结果返回。

2.PlatformViewIOS

PlatformViewIOS 是 PlatformView 的子类,也是其在 iOS 端的具体实现,当 PlatformViewIOS 接收到 message 时会交给 PlatformMessageRouter 处理。

PlatformMessageRouter 通过 PlatformMessage 中的 channel 找到对应的 FlutterBinaryMessageHandler,并将二进制消息其处理,消息处理完成后,直接调用 PlatformMessage 对象中的 PlatformMessageResponseDart 对象的 Complete 方法将二进制结果返回

3.结果回传

PlatformMessageResponseDart 的 Complete 方法向 UI Task Runner 添加了一个新的 Task,这个 Task 的作用是将二进制结果从 native 的二进制数据类型转化为 Dart 的二进制数据类型 response,并调用 Dart 的 callback 将 response 传递到 Dart 层。

Dart 层接收到二进制数据后,使用 MethodCodec 将数据解码,并返回给业务层。至此,一次从 Flutter 发起的方法调用就完整结束了

五、具体使用

6.png

1.Flutter 端调用 Android 方法

2.Android 端代码

1)继承 MethodCallHandler 并设置 Handler MethodChannel 需要保存在对象一会调用回调时需要使用,onMethodCall Flutter 层回调的方法这边用 RCIMFlutterWrapper 承接处理

7.png2RCIMFlutterWrapper 类中处理, MethodCall Method,对应 Flutter 层调用 invokeMethod 方法的传入的第一个参数,两端需完全对应一致

8.png

9.png

(3)直接通过 result 对象回调回去这样就能将结果回调

3.关于 Android 回调 Flutter 的使用

10.png

(1)Flutter 端回调监听,设置监听 Key 两端对应

 11.png

(2)Android 端代码回调, mChannel.invokeMethod 方法将数据回调给 Flutter 层



IM 消息数据存储结构设计

IM即时通讯admin 发表了文章 • 0 个评论 • 125 次浏览 • 2021-01-28 14:25 • 来自相关话题

1背景在移动互联网高速发展的时代,生活中 IM 类产品已经是我们离不开的应用了,像微信、钉钉等都是以 IM 为核心功能的社交产品。另外也有一些应用不是以 IM 为核心,但是也是其重要功能,比如在线游戏、电商直播等应用。在 IM 庞大的体系中,消息系统无疑是最核... ...查看全部

1背景

在移动互联网高速发展的时代,生活中 IM 类产品已经是我们离不开的应用了,像微信、钉钉等都是以 IM 为核心功能的社交产品。另外也有一些应用不是以 IM 为核心,但是也是其重要功能,比如在线游戏、电商直播等应用。

IM 庞大的体系中,消息系统无疑是最核心的,而消息系统中,最关键的部分是消息的分发和存储。

在以往传统消息系统中,对于在线的用户,消息会直接实时发送到在线的接收方,消息发送完成后,服务器端并不会对消息进行落地存储。对于离线的用户,服务器端会将消息存入到离线库,当用户登录后,从离线库中将离线消息拉走,然后服务器端将离线消息删除,这样的缺点是消息不持久化,导致消息无法支持消息漫游,降低了消息的可靠性。而在我们的消息系统中,服务器只要接收到了发送方发上来的消息,在转发给接收方的同时也会在离线数据库以及历史消息库中进行消息的落地存储,消息的落地也就支持了整体的消息漫游等相关功能。

 

2离线消息和历史消息的区别

离线消息,就是用户在离线过程中收到的消息,这些消息大多是用户比较关心的消息,具有一定的时效性。我们的系统设计,离线消息默认只保存最近七天的消息。离线消息在用户登录后会全量的获取,然后客户端根据会话进行整体离线消息的展示。

历史消息,存储了用户所有的消息,包括发的消息以及接收的消息。在客户端获取历史消息时,是按照会话进行分页获取的。历史消息的存储时间我们系统设计默认为半年,当然这个是可配置的。

3消息的发送以及存储的流程

融云整体的消息发送以及存储的流程如下图所示:

1.png

用户发送消息到服务器端后,首先会进入到消息系统中,消息系统会对消息进行分发以及存储。对于在线的接收方,会选择直接推送消息,但是遇到接收方不在线或者是消息推送失败的情况下,也会有另外的消息获取方式,接收方会主动向服务器拉取未收到的消息,但是接收方何时来服务器拉取消息以及从哪里拉取是未知的,所以消息存入到离线库的意义也就在这里。

   消息系统存储离线的过程中,为了不影响整个系统的更为平稳,融云使用了消息队列,消息是异步存入到离线库中的。

   在分发完消息后,消息服务会同步一份消息数据到历史消息服务中,历史消息服务会对消息进行落地存储。对于新的同步设备,会有消息漫游的需求,这也是历史消息的主要作用。在历史消息库中,客户端可以拉取任意会话的全量历史消息。

4 离线消息以及历史消息存储区别

   上述的图中我们能清晰的看到,离线消息我们存储介质选用的是 Redis,历史消息我们选用的是 HBase。为何选用不同的存储介质针对的是不同的业务场景和读写模式。下面我们重点介绍一下离线消息和历史消息存储的区别。

离线消息的存储模式是放大写,如下图所示,每个用户都有自己单独的收件箱和发件箱,收件箱存放需要向这个接收端同步的所有消息,发件箱里存的是发送端发送的所有消息。二人会话中的消息会产生两次写,发送者的发件箱以及接收端的收件箱。而在群的场景下,写入会被更加的放大,如果群里有 N 个人,那一条群消息就会被放大写 N 次。

放大写的优点是,接收端的逻辑会非常清晰简单,只需要从收件箱里读取一次即可,大大降低了同步消息所需的读的压力,但是缺点就是写入会被放大,特别是针对群这种场景。

2.png

历史消息的存储模式是放大读,因为历史消息中,每个会话都保存了整个会话的全量消息。在放大读这种模式下,每个会话的消息只保存一次。相比放大写的那种模式,写入次数大大降低,特别是针对群消息,只需要存一次即可。但是缺点是接收端接收消息非常的复杂和低效,因为这种模式客户端想拉取到所有消息就只能每个会话同步一次,读就会被放大,而且可能会产生很多次无效的读,因为有些会话可能根本没有新消息。

3.png

  IM 这种应用场景下,通常会用到写扩散这种消息同步模型,一条消息产生一条,但是可能会被读多次,是典型的读多写少的场景。一个优化好的系统,必须从设计上平衡读写压力,避免读或者写任意一个维度达到天花板。当然写扩展这种模式也有其弊端,比如万人群,会导致一条消息,写入了一万次。综合来讲,我们需要根据自己的业务场景做相应设计选择,我们的系统是根据了离线和历史消息的不同场景选择了写扩散和读扩散的组合模式。

5 客户端拉取消息

    离线消息的获取针对的是自己的整个离线消息,包括所有的会话。离线消息的获取是自上而下的方式,一次获取 200 条。在客户端拉取离线消息的信令中,需要带上当前客户端缓存的消息的最大时间戳,上面的图我们应该知道,离线消息我们存储的是一个线性结构,Server 会根据这个时间戳向下查找离线消息,重装或者新安装 App 时,客户端可以传 0 上来,Server 也会缓存客户端拉取到的最后一条消息的时间戳,然后根据业务场景,客户端类型等因素来决定从哪里开始拉取,如果没有拉取完 Server 会在拉取消息的应答中带相应的标记位,告诉客户端继续拉取,客户端循环拉取,直到所有离线消息拉完。

历史消息的获取针对的是单一会话,在拉取过程中需要带上来对方的 ID(如果是单聊的话就是对方的 UserID,如果是群,则是群组 ID 以及当前会话的最前面消息的时间戳,Server 会定位到这个人的这个会话然后一次获取 20 条,采用的是自下而上的方式,即从最后面往前翻。只要有消息,客户端可以一直向前翻,手动触发获取会话的历史消息。

 

6总结

   本篇文章主要讲了 IM 中消息系统的消息分发、存储等,重点介绍了离线消息和历史消息的区别以及两者存储中所选用的不同存储方式以及其优缺点。关于文中内容,也欢迎大家随时留言与我讨论。


融云 SDK 5.0.0 功能迭代

IM即时通讯融云技术团队 发表了文章 • 0 个评论 • 108 次浏览 • 2021-01-29 16:07 • 来自相关话题

融云 SDK 发布了 5.0 Dev 版本,在持续迭代新功能的同时,此版本对 IMKit SDK 进⾏了重构优化并且对外开源,SDK 初始化速度更快,同时减少了不必要的内存占⽤,针对 Android 库⽂件引⼊了加固技术,提升 App 安全性,详细如下:新增功... ...查看全部

融云 SDK 发布了 5.0 Dev 版本,在持续迭代新功能的同时,此版本对 IMKit SDK 进⾏了重构优化并且对外开源,SDK 初始化速度更快,同时减少了不必要的内存占⽤,针对 Android 库⽂件引⼊了加固技术,提升 App 安全性,详细如下:

新增功能

1.⾃定义多语⾔推送⽂案

功能描述:
根据⽬标⽤户设置的语⾔环境,从推送模板中选择对应语⾔的内容进⾏远程推送。

应用场景:
应⽤中存在多个国家的终端⽤户,在发送系统升级、运营活动类的通知时,需要给不同语⾔环境的⽤户推送不同的运营内容,可使⽤此功能设置多语⾔推送⽂案,增强运营效果,提升⽤户使⽤体验。

使用方式:
通过融云开发者后台,设置⾃定义推送模板,创建模板 ID。
终端⽤户通过 SDK 中 setPushLanguageCode 接⼝上报⽤户的语⾔环境。
SDK 或 Server API 发送消息时,携带后台创建的模板 ID(templateId),如⽬标⽤户未在线时,融云服务端会⾃动根据⽬标⽤户的语⾔环境选择对应的语⾔内容进⾏推送。


1.png

2.静默撤回消息功能

需要撤回⼀条消息,⼜不希望通知对⽅时,可以在撤回消息时设置 isDisableNotification 属性,设置后⽬标⽤户不会收到撤回消息时的通知栏提醒,⽀持通过 SDK 或 Server API 撤回消息时进⾏设置。

功能优化


  • 对 IMKit SDK 进⾏了代码重构并且开源,提升了 UI 品质及⽤户体验,解决了开发者在⽼版 IMKit 中某些 UI ⾃定义需求不能满⾜的问题。
  • 从 5.0 版本开始 Android IMKit SDK 使⽤ AndroidX 库实现,Google ⾃ support v7:28 开始,⼤部分 support 包都迁移到 AndroidX 下,建议开发者们尽早将项⽬转移到 AndroidX 下。
  • iOS IMLib 通讯能⼒库使⽤动态库技术,减少了不必要的内存占⽤,使 SDK 内存占⽤更⼩。
  • 对 SDK 整体性能进⾏优化,SDK 初始化速度更快,耗电更少。
  • Android SDK 引⼊了 Android 库⽂件加固技术,提升 App 安全性。
  • Android SDK 对 Android 11 系统进⾏了兼容适配。
  • 修复了 RTC SDK 的部分 BUG。

详细内容请查看官⽹版本更新描述:
IM 版本更新描述
音视频版本更新描述

RTC vs RTMP,适合的才是最好的!

WebRTC赵炳东 发表了文章 • 0 个评论 • 125 次浏览 • 2021-01-29 16:17 • 来自相关话题

随着在线教育、电商直播、泛娱乐社交等 App 的普及,实时音视频技术的应用需求也越来越多元化。目前,市场中能够支持音视频通信的主流技术有“RTMP+CDN”和“RTC”两大阵营。选型时,开发者如何根据场景选择更适合自己的通信技术?这就要从两者的技术特点、价格、... ...查看全部

随着在线教育、电商直播、泛娱乐社交等 App 的普及,实时音视频技术的应用需求也越来越多元化。目前,市场中能够支持音视频通信的主流技术有“RTMP+CDN”和“RTC”两大阵营。选型时,开发者如何根据场景选择更适合自己的通信技术?这就要从两者的技术特点、价格、厂商服务综合考虑。1.png

RTMP+CDN 技术特点与适用场景

RTMP (Real Time Messaging Protocol)基于 TCP 的流媒体传输协议,最大的特点是与 CDN 的强绑定,需要借助 CDN 的负载均衡系统将内容推送到接近用户的边缘节点,使用户就近取得所需内容,提高用户访问的响应速度和成功率,解决因分布、带宽、服务器性能带来的访问延迟问题。更多适用于站点加速、点播、短视频等场景。

对于初次通过 CDN 服务来实现音视频通信的开发者来说,技术指标应主要关注延时、卡顿率、下载速度、打开速度、回源率、宽带冗余提升率等几个维度。

有研究表明,在 0.1s 以下的延迟,用户几乎是无感知的;1s 左右的延迟,用户会明显注意到延时的发生,但在该时间内思维依然是连贯的;超过 10s 的延时,用户会失去等待的耐心。在所有关键技术指标中,控制延时是 CDN 最需要提升的。

以直播场景为例,延时主要看 2 个核心指标:首播时间和再缓存时间。首播时间即从打开到看到视频画面的时间,会受域名解析、连接、第一包时间的影响,首播时间控制在 1 秒内算是不错的效果。其次是再缓冲时间,是用户观看视频时的卡顿时间。由于实际服务中视频长度不一,一般会做播放的体验统计,主要监测的是卡顿率。行业内而言,直播首播时间 300ms,卡顿率在 15% 以下算是优质的通信服务。

目前的 CDN,通常有 3-5 秒的延迟,在浏览图片、短视频等内容时用户感知不明显,对于不需要实时强互动的直播,比如体育赛事网络直播、演唱会网络直播、新闻现场直播,延迟是可以接受的,并不会影响用户体验。

2.png

而在线视频会议、在线教育、电商直播、远程医疗会诊这些对互动有非常高要求的场景,RTMP+CDN 的模式与这些场景对于低延时、无卡顿的要求有一定差距。这时,选择 RTC 技术才能更好地满足开发者的需求。

RTC 技术特点与适用场景

说到 RTC(Real Time Communication)实时音视频通信,它最大的特点就是低延时和无卡顿。从功能流程上说,它包含了采集、编码、前后处理、传输、解码、缓冲、渲染等诸多环节,RTC 不是靠“优化”各环节去实现的实时互动,而是依靠推流端实时的传输机制。

3.png

很多实时音视频服务专业厂商使用的就是 WebRTC 标准,这是一种基于浏览器的实时通信的开源解决方案,使用 UDP 私有协议来进行媒体推流,而不需要创建离散的媒体段;并且它是面向无连接的,没有 TCP 连接断开时的挥手确认连接关闭的机制,基于这两点,WebRTC 能够做到毫秒级的低延迟,远远低于基于 RTMP 协议的 CDN 分发的延迟。而且,它直接通过浏览器就可以完成推流和播放,对于开发者接入来说实在太方便。

因此,WebRTC 标准针对有高互动性要求的直播场景尤为适宜。以直播连麦为例,主播端把通信直播流发到观众端,同时也可以把观众端拉上麦,实现主播和观众的互动。使用 WebRTC,内容实时传输,主播和观众可以进行音视频连麦互动,实时沟通,延时一般低至 400ms 以内。

4.png

基于 WebRTC 标准的融云实时音视频服务,拥有超低延迟的优势,同时也支持将 RTC 音视频流合流(MCU)转码为 RTMP,并推流到第三方 CDN 上,保留了标准协议普遍被 CDN 网络支持的好处。目前,融云音视频通话,可做到全球端到端延时小于 400ms,最低延时 66ms;低延时互动直播的直播推流可以做到主播观众间延迟在 300ms 左右,保障端到端之间延迟无感知的实时互动。

CDN vs RTC 选型还需看价格服务综合比

一套实时音视频通信能力的搭建,除了要根据场景选择适合的技术外,还要看价格、服务的综合性价比。通常来说,使用 RTC 技术的成本比 RTMP+CDN 高。因为,从实践来看,UDP 传输比 TCP 传输对资源消耗要多,而且重传、封包、FEC 冗余计算等都会额外增加计算量,在多进程模式下可能还会遇到内存资源的过多消耗,这些都导致开发及使用成本的增加。

开发者选型中,性价比需综合技术特点、适用场景、价格和服务四个方面的全面考量。服务在产品上线前后的开发阶段和运营阶段,都要发挥重要作用。目前,开发者服务做得比较好的厂商比如融云,会与开发者共建开发文档,技术手册短视频化,提供场景化的 Demo,以及在官网搭建开发者专区,帮助开发者更便捷、更快速的理解 SDK。

融云全新升级的实时音视频服务,提出“以一套 SDK 解决所有通信场景”,使用融云 RTC 的开发者,同时可以用融云 IM 作为信令通道,而不用自己重新搭建或选择第三方信令通道,这样可以大大提升开发效率,减少 SDK 文档学习时间。

总体而言,RTC 低延迟直播是未来发展的趋势,而 RTMP 在当前依然拥有价格上的优势,而两者作为音视频领域的实用技术,无论是适用场景、还是贴近开发的服务都越来越多样化,开发者未来选型之路也将更顺畅。



美国、日本、俄罗斯版“微信”大PK,即时通讯软件如何流量变现?

IM即时通讯赵炳东 发表了文章 • 0 个评论 • 114 次浏览 • 2021-02-03 17:12 • 来自相关话题

即时通讯软件可以说是互联网时代的基础设施了,从全球范围看,虽然各类即时通讯软件如雨后春笋般出现,但是真正能留在消费者手机中的却凤毛麟角,本文将主要对比美国版微信Whatsapp、日本版微信Line以及俄罗斯版微信Telegram的主要盈利模式。壹美国微信Wha... ...查看全部

即时通讯软件可以说是互联网时代的基础设施了,从全球范围看,虽然各类即时通讯软件如雨后春笋般出现,但是真正能留在消费者手机中的却凤毛麟角,本文将主要对比美国版微信Whatsapp、日本版微信Line以及俄罗斯版微信Telegram的主要盈利模式。

壹美国微信Whatsapp:拒绝广告,赚B端的钱2009年,Jan Koum和Brian Acton开发了一款用于“状态更新的APP”,并将之命名为“Whatsapp”。当这个软件升级到2.0的时候,也就真正开始了其作为即时通讯软件的生涯。
作为一个拥有16亿月活(MAU)用户的超级APP,网络效应早已经形成,但是如何赚钱成了问题——因为其开发者鲜明地表达了拒绝通过广告赚钱的逻辑。

1.jpg

按照Whatsapp开发者的观点,他们希望能为用户创造一个即时通讯平台,而不是为企业创造一个放广告的平台。于是,起先的逻辑是收取每个用户每年1美元的订阅费。
这时候就不得不提及Whatsapp的融资历程了:它的第一轮融资来自5位前雅虎的朋友,总额为25万美元;而它的第二轮和第三轮投资者就值得一说了,那就是大名鼎鼎的红杉资本(Sequoia Capital),总额6000万美元(2011年800万美元,2013年5200万美元)。
这些融资基本就负担了Whatsapp公司的所有开销,考虑到运营这个项目的成本并不是很高——事实上,主要的开销是向用户发送验证码,所以Whatsapp取消了向C端收取1美元/年订阅费的做法。
之后,当Whatsapp再次进入视野的时候,就是Facebook的扎克伯格收购Whatsapp了:在追逐Whatsapp长达2年之后,2014年2月,Facebook以190亿美元收购Whatsapp,而创始人Jan Koum也得以加入Facebook董事会。
收购之后,Whatsapp的价值就显现了:Facebook不仅将之视为一个用户数据的“留量池”,更将之纳入自己的生态体系。
Facebook推出了Whatsapp Business Application,也就是商业版Whatsapp,这样企业就可以在上面建立自己的官方档案,并得到系统认证。在档案中,这些企业可以将自己的网站链接、Facebook主页链接挂上去,甚至可以将他们的座机号连在Whatsapp中。

目前,商业版Whatsapp对于企业来说依然免费,Whatsapp是通过商业API赚钱。 Whatsapp商业API可以把Whatsapp和企业的系统进行整合,通过通知让企业和消费者接触。为了避免垃圾信息,Whatsapp限制了企业发送消息的能力,只有消费者首先联系了公司以后,公司才可以联系消费者(这点和微信的公众平台非常相似),不过API也可以帮助企业向消费者发送送货确认、活动门票等,目前Whatsapp的商业API已经和Booking.com等客户进行了深度合作。

至于Whatsapp如何通过API赚钱,那就很有趣了,Whatsapp向回复缓慢的企业收取费用。
正常情况下,当消费者联系企业后,企业可以在24小时内回复,这是免费的;但是时间一旦超过24小时,此时API就会收费,其费用是固定的,根据国家有所不同。
听起来似乎是一个特别蠢的收费逻辑,但是对于那种百万级用户的企业来说,这就卡住了咽喉:一个订票网站怎么可能同时处理百万级用户的咨询呢?所以这个需求是确实存在的。

此外,在印度,Whatsapp还有支付功能,这可能帮助Whatsapp成为当地用户首选的“寄钱APP”——就像Venm一样,这也可以成为未来的盈利点。
在F8大会上,扎克伯格也提到了这一点,未来他将把Whatsapp的支付功能拓展到更多国家,这对于希望从Whatsapp的网络效应中赚钱的商家,有极大吸引力。
至于盈利数据,Whatsapp目前没有公开过财报,来自福布斯(Forbes)的估算显示,其年收入约50亿美元,ARPU在2020年可以达到4美元。

贰日本微信Line:广告为生,内容为辅在亚洲,Line主要流行于日本、泰国、印尼和中国台湾地区,该公司成立于2000年9月,于2016年7月同时在日本、美国的纽约证交所上市,其主要股东是韩国搜索引擎巨头Naver。
从Line的财报看,2019年4季度(财年截止于2019年12月31日)它的营业收入达到608亿日元,同比增长8.6%,按照地区划分,71%的收入来自日本,29%来自海外。
同期,其在日本的MAU同比增加5.1%,季度MAU达到1.64亿,同时DAU/MAU也达到了79%,也证明了Line的用户活跃度。
从收入角度看,Line共有3个核心收入源,按营收占比,第一是广告(55.4%),第二是交流/内容/其他(29.8%),第三是战略业务(14.8%)。
在广告方面,Line主要是展示广告(Display Ads)和账号广告(Account Ads),二者占总广告收入的93.2%,而展示广告收入同比增长达到65.4%。考虑到Line为各类商家提供大量广告服务,这个成为核心收入源也就十分正常了。

Line的第二大收入源是交流/内容/其他,这部分收入比较稳定,占比超过一半的是内容部分,分别是音乐业务Line Music和漫画业务Line Manga,目前音乐业务同比增长超过40%,漫画业务也有20.1%。
继续往下挖一层,值得一提的是两点,第一点是Line的内容业务,这一部分可以简要称之为“贴纸、壁纸”。用户可以在“主题商店”和“贴图商店”中充值“Line积分”购买壁纸和表情包。

这部分可以和微信进行对比:在微信上,艺术家可以制作表情上架微信,用户对表情的打赏将直接进入艺术家账户。

第二点是“其他”,根据其财报显示,这部分主要是研究业务“Line Research”,财报写道:“有超过500万用户注册成为问卷答卷人,此项业务依然在稳健增长”,为企业提供用户调查,这也属于是对用户的货币化方法之一了。
最后是Line的第三大收入源,Line在财报中将之称为“战略业务(Strategic)”,2019Q4总收入为90亿日元,其中51亿日元收入来自IP业务“LINE FRIEND”,这里主要销售IP赋能的玩具、文具、日用品等;另外的39亿日元来自O2O/电商、Fintech和AI业务。

不过,这里更值得注意的是Line打造的支付业务“Line Pay”,2019Q4,其全球GMV达到3550亿日元,全球MAU达到650万,相比2019Q3分别增长680亿日元和100万。

整体而言,Line的收入源还是比较多的,在广告收入之外,主要是内容(漫画、音乐、表情)、IP变现以及支付业务。对于Line来说,广告和支付业务成为重要收入源并不难以想象,而内容业务的收入更多是和日本等地用户对于漫画、音乐、IP等的认可,以及二次元环境密不可分的。

叁,俄罗斯微信Telegram:绝对免费、绝对安全,发币赚钱对于不少国内用户来说,Telegram的火爆得益于曾经的“发币狂潮”——大量用户为了获得糖果空投(Airdrop)而注册Telegram,加入“电报群”。
相比于其他即时通讯软件,Telegram主打两点,第一是永远免费,第二是绝对加密。
事实上,在成立之初,Telegram就主打“隐私(Privacy)”,其创始人Pavel Durov在2013年创建Telegram,并在短时间内实现爆炸性用户增长,他曾说,在推出Telgram的15个月后,用户在Telegram上就发送了10亿条信息,而VKontakte(这是Durov之前的创业项目)花了6年半才做到的里程碑。
他同时写道,“Telegram的5000万用户均匀地分布在各个大陆,最活跃的用户来自西班牙、巴西、韩国、墨西哥、德国、马来西亚、新加坡、印度、沙特、意大利和美国,而俄罗斯的比例是1%。”
至于所谓的安全性,其实不必看Telegram的官方介绍,只需要看新闻就可以了:
据Trend Micro发布的一份关于恐怖分子通讯方式的研究报告显示,34%的恐怖分子使用Telegram进行沟通,该研究也证实了此前有关极端组织“伊斯兰国(ISIS)”使用Telegram进行秘密信息交换。
和Whatsapp类似,Telegram也不通过广告赚钱,同时还保持了开源的特性,截止到2019年,Telegram没有盈利,或者说没有创造过收入,其创始人Durov在一篇博客上写道,如果资金不足,他可能会引入“非必要的付款选项(non-essential paid options)”来给程序员发工资。
传统的收入来源都没有,Telegram却有“新的收入来源”,那就是“发币”。
2018年1月到3月,Telegram进行了代币首次发行。其白皮书显示,Telegram的加密代币被命名为“Gram”,总发行量为50亿,其中52%用于开发、44%用于代币首次发行,以及余下4%给予团队。
Telegram的区块链网络名为“TON”,该区块链项目将分为四个分支:TON服务、TON DNS、TON支付和TON区块链。
最后,这场宏大的代币首次发行募集了约17亿美元(全世界的投资者购买了约29亿个Gram代币),而来自今年1月初的报道显示,美国证券交易委员会(SEC)提交了一份法院指令,要求Telegram解释代币首次发行所产生的资金是如何使用的。不过迄今为止,Telegram一直拒绝公开账目,并且表示Gram不是有价证券(Security)。
Ton网络原定于2019年10月上线,但美国证券交易委员会将 Telegram 的上线日期推迟到了2020年4月。所以目前没人说的清Telegram到底是用这笔钱干了什么,只能关注今年4月份会不会有新的消息,并希望这一场代币首次发行不是一场闹剧。

总结整体来说,可以发现,即时通讯软件们虽然最终盈利模式并不相同,但是发展模式非常接近,可以抽象为:
1.0时代,免费的时代,主打用户之间的连接、交流,这个时代以两个“结论”作为最终答卷,APP本身看,就是DAU、MAU和用户数,而从外部看就是在市场内的占有率;
2.0时代,赚钱的时代,一般来说,APP在此时已经在一个地区成为至少是Top2的巨头,沉淀了海量用户,此时B端企业就会盯上这个APP,开始做营销、服务,而APP就可以“顺坡下驴”为这些B端企业开发功能模块,进行服务抽成——例如GMV抽成,基本来说在这个领域,中国的微信早已走在了前面。

(来源于公众号-零售威观察)

关于高阶JAVA枚举你不知道的事!

科技创新赵炳东 发表了文章 • 0 个评论 • 99 次浏览 • 2021-02-03 17:12 • 来自相关话题

JAVA枚举,比你想象中功能还要强大!我经常发现自己在Java中使用枚举来表示某个对象的一组值。在编译时确定类型可以具有什么值的能力是一种强大的能力,它为代码提供了结构和意义。当我第一次了解枚举时,当时我认为它们只是一个为常量命名的工具,可以很容易地被静态常量... ...查看全部

微信截图_20210203171135.png

JAVA枚举,比你想象中功能还要强大!

我经常发现自己在Java中使用枚举来表示某个对象的一组值。

在编译时确定类型可以具有什么值的能力是一种强大的能力,它为代码提供了结构和意义。

当我第一次了解枚举时,当时我认为它们只是一个为常量命名的工具,可以很容易地被静态常量字符串ENUM_VAL_NAME所取代。

后来我发现我错了。事实证明,Java枚举具有相当高级的特性,可以使代码干净、不易出错,功能强大。

让我们一起来看看Java中的一些高级枚举特性,以及如何利用这些特性使代码更简单、更可读。

枚举是类!

在Java中,枚举是Object的一个子类。让我们看看所有枚举的基类,Enum<E>(为简洁起见进行了修改)。

public abstract class Enum<E extends Enum<E>>
    implements Constable, Comparable<E>, Serializable {
  private final String name;
  
  public final String name() {
      return name;
  }
  
  private final int ordinal;
  
  public final int ordinal() {
      return ordinal;
  }
  
  protected Enum(String name, int ordinal) {
      this.name = name;
      this.ordinal = ordinal;
  }
  
  public String toString() {
      return name;
  }
  
  public final boolean equals(Object other) {
      return this==other;
  }
  
  public final int hashCode() {
      return super.hashCode();
  }
  
  public final int compareTo(E o) {
      Enum<?> other = (Enum<?>)o;
      Enum<E> self = this;
      if (self.getClass() != other.getClass() && // optimization           self.getDeclaringClass() != other.getDeclaringClass())
          throw new ClassCastException();
      return self.ordinal - other.ordinal;
  }
}

我们可以看到,这基本上只是一个常规的抽象类,有两个字段,name和ordinal。

所以说枚举都是类,它们具有常规类的许多特性。

我们能够为枚举提供实例方法、构造函数和字段。我们可以重写toString(),但不能重写hashCode()或equals(Object other)。

接下来我们看下我们的枚举示例,Operation

enum Operation {
    ADD,
    SUBTRACT,
    MULTIPLY
  }

这个枚举表示一个Operation可以对两个值执行,并将生成一个结果。关于如何实现此功能,您最初的想法可能是使用switch语句,如下所示:

 public int apply(Operation operation, int arg1, int arg2) {
    switch(operation) {
      case ADD:
        return arg1 + arg2;
      case SUBTRACT:
        return arg1 - arg2;
      case MULTIPLY:
        return arg1 * arg2;
      default:
        throw new UnsupportedOperationException();
  }
}

当然,这样子会有一些问题。

第一个问题是,如果我们将一个新operation添加到我们的Operation中,编译器不会通知我们这个开关不能正确处理新操作。

更糟糕的是,如果一个懒惰的开发人员在另一个类中复制或重新编写这些代码,我们可能无法更新它。

第二个问题是默认情况default,每段程序里面都是必需的,尽管我们知道在正确的代码里它永远不会发生。

这是因为Java编译器知道上面的第一个问题,并且希望确保我们能够处理在不知情的情况下向Operation中添加了新枚举。

还好,Java8用函数式编程为我们提供了一个干净的解决方案。

函数枚举实现

因为枚举是类,所以我们可以创建一个枚举字段来保存执行操作的函数。

但是在我们找到解决方案之前,让我们先来看看一些重构。

首先,让我们把开关放在enum类中。

 enum Operation {
  ADD,
  SUBTRACT,
  MULTIPLY;
  
  public static int apply(Operation operation, int arg1, int arg2) {
    switch(operation) {
      case ADD:
        return arg1 + arg2;
      case SUBTRACT:
        return arg1 - arg2;
      case MULTIPLY:
        return arg1 * arg2;
      default:
        throw new UnsupportedOperationException();
    }
  }
}

我们可以这样做:Operation.apply(Operation.ADD, 2, 3);

因为我们现在从Operation中调用方法,所以我们可以将其更改为实例方法并使用this,而不是用Operation.apply()来实现,如下所示:

public int apply(int arg1, int arg2) {
  switch(this) {
    case ADD:
      return arg1 + arg2;
    case SUBTRACT:
      return arg1 - arg2;
    case MULTIPLY:
      return arg1 * arg2;
    default:
      throw new UnsupportedOperationException();
  }
}

像这样使用:Operation.ADD.apply(2, 3);

看起来变好了。现在让我们更进一步,通过使用函数式编程完全消除switch语句。

enum Operation {
              ADD((x, y) -> x + y),
              SUBTRACT((x, y) -> x - y),
              MULTIPLY((x, y) -> x * y);
  
              Operation(BiFunction<Integer, Integer, Integer> operation) {
                      this.operation = operation;
              }
  
              private final BiFunction<Integer, Integer, Integer> operation;
  
              public int apply(int x, int y) {
                      return operation.apply(x, y);
              }
  
  }

这里我做的是:

  • 添加了一个字段 BiFunction<Integer, Integer, Integer> operation

  • 用BiFunction创建了用于Operation的构造函数。

  • 调用枚举定义中的构造函数,并用lambda指定BiFunction<Integer, Integer, Integer>。

这个java.util.function.BiFunction operation字段是对采用两个参数的函数(方法)的引用。

在我们的例子中,两个参数都是int,返回值也是int。不幸的是,Java参数化类型不支持原语,所以我们必须使用Integer。

因为BiFunction是用@functioninterface注释的,所以我们可以使用Lambda表示法定义一个。

因为我们的函数接受两个参数,所以我们可以使用(x,y)来指定它们。

然后我们定义了一个单行方法,它使用 ->x+y 返回一个值。这相当于下面的方法,只是更简洁而已。

  class Adder implements BiFunction<Integer, Integer, Integer> {
          @Override           public Integer apply(Integer x, Integer y) {
                  return x + y;
    }
  }

我们的新Operation实现采用相同的方式:Operation.ADD.apply(2, 3);.

但是,这种实现更好,因为编译器会告诉我们何时添加了新Operation,这要求我们更新函数。如果没有这一点,如果我们在添加新Operation时还不记得更新switch语句,就有可能得到UnsupportedOperationException()。

关键要点

  • Enum枚举是Enum的扩展类。

  • Enum枚举可以有字段、构造函数和实例方法。

  • Enum枚举字段可以存储函数。与lambda配合使用,可以创建干净、安全的特定于枚举的函数实现,并在编译时强制执行它们(而不是使用switch)。

下面是这个示例的GitHub地址。(https://github.com/alex-power/java-enum-example)

本文参考:https://medium.com/javarevisited/advanced-java-enum-features-you-need-to-know-b516a191c7e2

(来源于公众号:程序猿DD)


开源商业模式正在被云服务商杀死!

科技创新柠檬^ 发表了文章 • 0 个评论 • 49 次浏览 • 2021-02-03 17:20 • 来自相关话题

对程序员圈子来说,Mapbox是一家专注于地图绘制的卓越软件公司。从Mapbox GL JS(他们的2D地图渲染器)到自动驾驶和导航库,再到增强现实、3D可视化,甚至视频游戏技术,Mapbox在这一领域做到非常棒,其创新成果占有巨大的市场份额。而且这些内容都是... ...查看全部

对程序员圈子来说,Mapbox是一家专注于地图绘制的卓越软件公司。从Mapbox GL JS(他们的2D地图渲染器)到自动驾驶和导航库,再到增强现实、3D可视化,甚至视频游戏技术,Mapbox在这一领域做到非常棒,其创新成果占有巨大的市场份额。而且这些内容都是开源的,也是让众多程序员喜欢他们的原因之一。

但是昨天看到了一个让我震惊的新闻:最新版本的Mapbox GL JS将不再是开源的!!!

作为个人来说,我并非是一个完美的热衷于开源的粉丝,因为我知道,创建和维护开源代码是多么一件吃力不讨好的事情,真的是非常累人,所以我一直很尊敬那些愿意开源的程序员,并且哪怕是开源,哪怕是对方过去已经丢弃不用的想法,我都觉得自己没有权力肆意使用对方的想法和知识产物。

但是同样的,直到昨天看到那个新闻之前,我仍然对商业开源软件抱着些许的客观、浪漫、自欺欺人的想法。在我的想法中,这是一个在当下重名利的世界中,保持着那颗开源的心,一直以开源做为自己的商业模式,持续走下去的童话故事,而Mapbox就是故事的主角,

去年的时候我也写过关于Mapbox商业模式的文章,就是他即提供了一种免费开源的版本,也提供了一种收费的版本,这些收费版本当然有一些独到的免费版本没有的功能。 听起来,有点像王者荣耀中有皮肤和没皮肤的概念。

如果对开源的商业模式有进一步了解兴趣的,建议可以看下Joseph Jacks的博文,链接地址如下:https://medium.com/open-consensus/2-open-core-definition-examples-tradeoffs-e4d0c044da7c

在最初的时候,没有人相信这种模式管用,但是随后发生的一切让人大跌眼睛,像Elastic、D2iQ(以前的Mesosphere)、MongoDB和Cloudera这样的几十家公司,都通过这种过往没出现过的方式,成功赚取了数十亿美元的投资。当然和现在相比,那个时候他们开放的开源版本可是开放好多。

直到今天,看了那个新闻之后,我们不由得感慨,开源模式即将死去!

那是什么让他从一时兴旺到如今的一命呜呼呢?

云服务商!

我们先回到Mapbox的例子,在Mapbox GL JS使用的案例中,Mapbox最早的决定是,开源其基于浏览器的地图渲染器的最早的两个版本(像我们熟知的Snap-Maps、纽约时报和CNN都用过)。自2014年首次发布以来,它在web开发人员中一直非常流行。一旦你知道你在找什么,你就会开始到处看到它。

微信图片_20210120152742.png

而对于我自己来说,当我的团队开始构建一个标记卫星图像的项目时,我才亲身体验了Mapbox GL JS的功能是有多么强大。使用Mapbox GL JS的功能,支持复杂几何图形的自由形式绘图,最终的成品是可以在地图上形成形状,也就是说是我的标记是被投影到地球上的一个真实位置,而不是简单的仅仅是悬浮在想象中的二维空间。这种效果让人感觉明显和直截了当,非常好用。

但事实上如果我不用Mapbox GL JS,从零开始设计就会非常非常困难。因为即使是用徒手画的简单形状也可以包含数千个单独的点。这样的话很快,我的屏幕上就会被数十万个顶点的形状填满,然后很显然,我的浏览器就会崩溃。而Mapbox GL JS是通过调用计算机上图形卡来帮助解决这个问题,如果不依靠Mapbox那几万小时的艰苦的工程工作,我们不可能在预算和时间有限的情况下完成该功能。Image for post

而这周Mapbox决定公布一个Mapbox GL JS的新版本,这个新版本不再开源瞬间震撼到了我!不仅仅是因为之前的V1版本是一个广受欢迎的开源版本,而是因为Mapbox作为一个开源代码的代名词给予我的那种崇高的敬意。在我的看法里,如果你要描述Mapbox是一家怎么样的公司而不提到开源,就像你和一个从未喝过的人谈到巧克力牛奶时不说这是一种液体一样!

Mapbox迄今为止,仍拥有超过800个开源项目,并在Github公共存储库活动方面一直名列全球前40名。并且Mapbox一直在给世界上知名度最高的开源软件贡献者提供各种工作机会,不仅仅是地图行业。

所以说,到底突然发生了什么?

其实,一切都源头还都是因为开源不再是一个在当下这个时代能站得住脚的商业模式!

Mapbox选择保持Mapbox GL JS的V2版本的专有权而不再开源就是一个强烈的信号。虽然这信号背后到底代表着什么还不是很清楚,但是已经让我咬牙切齿。。。

在我看来,这已经意味着我们要迎接一个时代的结束,这预示着代表着开源这种商业模式的寿命的终结!

其实我的潜意识里一直有着这个想法,早在Mapbox的新闻之前,但是Mapbox的新闻是真正为我心中猜想敲上实锤的那最后一击。

为了了解即使像Mapbox这样的公司也决定从开源转变的原因,我觉得可以先看下Mongo DB和Redis Labs这两个行业同行之前已经发生过的故事。

就在两年前,知名科技博主Ben Thompson写过一份文章,文章中阐述了一份总结关于AWS(Amazon Web Services——Amazon云服务), MongoDB和开源代码的经济回报。按他的说法就是:如果你提供了你的独家代码作为开源代码,并且让它变得流行起来,那么那些云服务商必然将用这些代码来为他们自己所用,为他们制造一些竞争性的服务,就好比用你制作的武器来攻击你一般,并且他们的心中没有丝毫歉意和犹豫,他们的眼中只有利益,对于这种行为,你的律师最后只会对你说一句无能为力,因为你曾经自己将这些内容开源了!

Ben在文中提到AWS推出了一项与MongoDB和Redis的付费产品直接竞争的对手服务,但也没有完全击败对手。事实上,自从那个时候起,MongoDB的股价从那时起已经上涨了275%,Redis在几个月前刚刚筹集了1亿美元,正式跨过了10亿美元的神奇估值门槛。

微信图片_20210120152751.png

但我想表述的更重要的不仅仅是Mongo和Redis在受到AWS的攻击后依旧蓬勃发展,而是他们是如何做到的?

这两家公司都以公司一贯的方式反击:一支知识产权的律师大军。

Redis采取了一种策略,在现有开源工具的更新版本中加入了一个有着严格限制性条件的commons条款,不过这让一些著名的开源代码的支持者非常不满:

微信图片_20210120152753.png

鉴于此,Redis后来用了另外一种方法,申请了一个完全新颖和独特的许可证,虽然这不会比commons条款更糟,但几乎可以肯定的是也不会更好。

另一家公司MongoDB呢?它也采取了俗称poison pill(毒丸) 的法律策略,在AWS推出竞争性的服务后不久,它就为自己的软件申请了一个新的、同样是虚构的许可证Server-Side Public License (SSPL)。

这些动作都是为了对抗云服务商的一系列举措。

更准确的说,他们的开源产品对任何有规模的公司都会起到使用时是否合规这个问题。

当然,这么做的代价就是Redis和Mongo从根本上减少了开源的开放性。从结果看,他们做的很好,虽然这是以牺牲了它们最初的理想为代价的,但毕竟活着是最重要的。

但是很多开源作者觉得自己被出卖了一样,我能理解他们的感受,但是我也理解Redis或MongoDB这么做是理性的生意行为。

回到Mapbox上,至少已经有一家云服务商公开的将Mapbox的代码复制并粘贴到他们的收费服务中: Azure,微软的云服务

去年,Azure发布了由Mapbox GL JS支持的地图样式,它是Azure地图服务的一个关键特性。为此,Mapbox甚至在他们公司的博客上写了一个声明。

虽然我们可以理解为Mapbox写这个声明是件好事,但我严重怀疑这是导致了Mapbox GL JS不再开源的开始。毕竟,在竞争无比激烈的公共云世界里,一旦一个云服务商开始提供服务,其他服务商肯定很快就照猫画虎一样开始提供类似服务。Mapbox终于发现自己的处境与MongoDB和Redis是如此的相似:它们在为那些万亿美元的科技巨头免费提供研发基础!

与Mongo和Redis不同,Mapbox最终还是抵抗了一些冲动。他们没有改变产品开源部分的基本许可证,而是彻底打破了这一局面。旧版本仍然是一个成熟且非常有用的版本,将保留其原始的许可证。同时Mapbox召集社区成员无限期地维护这个版本,我希望这会有用。

而新版本将保持一定程度的公开(例如代码都发布在Github上)。但是它不再是开源那样的了。对我来说,这感觉是一个更诚实的方法,而不是试图用一个没见过的、完全未经证实的许可证或一些“看似明白”的条款来穿针引线制造一种假象。

有些人可能会觉得这是一场悲剧,因为这意味着社区捐献可能会减少。诚然,尽管贡献者名单很长,但Mapbox的现任和前任员工还是贡献了最大的份额。但是这个项目已经吸引了一个庞大的、全球性的工程师群体,他们用它来建造东西,对它进行技术讲座。毫无疑问,昨天对于那些充满创作热情的用户来说的确是一个悲伤的日子。他们会继续过下去,但肯定有一种莫名的失落感。

至于这么做是否偏离了Mapbox最初的使命或公司文化?我想这条来自一位自公司成立以来一直在公司工作的现任员工的微博很好的总结了这一点:

微信图片_20210120152756.png

现实中很多事情都是很无奈的,毕竟我们要吃饭要生存下去。

很久以前我天真的以为围绕开源建立一家公司是很容易的,并且其他人都会很道德的使用这些开源的信息,但是现在我不再敢肯定这些。

我仍然相信开源是世界上一股强大的向善力量。我仍然认为,有的公司可以战略性地、认真地为开源做出贡献,不仅为自己的使命服务,也为集体利益服务。

但是,相对的,我再也不相信那些靠着风投存活下去的公司能够负责任地推行这种策略,将软件作为其价值主张的核心。我不再认为这是一个可行的模式,因为或快或慢,他们都会被他们的野心所吞噬,因为如果不这么做,他们最终只能在被自己的武器干掉和背叛最初的理念中间二选一。

昨天真是令人难过的一天。不仅仅因为Mapbox的宣布令人失望,而且就在昨天,我终于不得不向自己承认一点:

云服务商真的杀死了开源!

(来源于公众号:程序猿DD)


关于密码你不知道的冷知识?至今还有 3% 的人使用“123456”作为密码

科技创新fanta2 发表了文章 • 0 个评论 • 77 次浏览 • 2021-02-04 10:11 • 来自相关话题

之前我们报导过 2020年被用烂大街的密码《2020 最烂密码 TOP 200 曝光!》,500 多万个泄漏密码表明,共有近 3% 的人使用“123456”作为密码。而最近知名黑客网站 Have I Been Pwned 上一个密码“ji32k7au4a83”... ...查看全部

之前我们报导过 2020年被用烂大街的密码《2020 最烂密码 TOP 200 曝光!》,500 多万个泄漏密码表明,共有近 3% 的人使用“123456”作为密码。而最近知名黑客网站 Have I Been Pwned 上一个密码“ji32k7au4a83”的使用次数引起了热烈讨论。

Have I Been Pwned 是一个可以查询用户的邮箱是否被泄漏的网站,它的一个密码查询功能 Pwned Passwords 记录着在数据泄露中暴露的 551 509 767 个真实密码,用户可以在这里查询某个密码被使用的次数。比如查询一下 2018 年最烂密码“123456”,得到 23 174 662 次的结果:

1.jpg

“123456”这样简单易记的数字串被很多人作为密码使用,这很容易理解,但是有一个密码 “ji32k7au4a83”的使用次数让人费解,并且在最近引起了热烈讨论。

硬件/软件工程师 Robert Ou 最开始在 Pwned Passwords 上发现“ji32k7au4a83”竟然有 141 次使用,他觉得这不太正常,因为这个字符串太“偏”了,于是他在社区提问。

随后就有人指出了原因(估计就是使用者),原来“ji32k7au4a83”是汉语注音符号系统中“我的密码”的对应字符串。

汉语注音符号是以章太炎的记音字母作蓝本,1913 年由中国读音统一会制定,1918 年北洋政府教育部正式颁行的一套注音系统。

2.png

1918 年第一个版本如下:

声母介音韵母
ㄍㄎㄫㄐㄑㄬㄉㄊㄋㄅㄆㄇㄈㄪㄗㄘㄙㄓㄔㄕㄏㄒㄌㄖㄧㄨㄩㄚㄛㄝㄟㄞㄠㄡㄢㄤㄣㄥㄦ

经过一个多世纪的发展,目前注音符号已经变化不少。目前中国台湾、澎湖、金门与马祖仍在使用注音符号,详情可以查看百科。

3.jpg

以上中招的朋友看完本文请记得修改密码。

据说,黑客会根据网民习惯设置的密码,收集起来编写成为“常用密码库”,直接使用现成的常用密码库去匹配破解,往往就能短时间破解大量账号。有安全机构研究显示,黑客大约只要17分钟就可以破解1000个帐号。

那我们平时该如何去设置密码呢?

安全专家的建议是,设置密码满足这三点:

  1. 密码长度最好8位或以上;

  2. 密码没有明显的组成规律;

  3. 尽量使用三种以上符号,如“字母+数字+特殊符号”。


AWS回应Elastic修改开源协议:创建“真正”开源的Elasticsearch分支

科技创新fanta2 发表了文章 • 0 个评论 • 89 次浏览 • 2021-02-04 10:11 • 来自相关话题

来源于公众号“程序猿DD”前几天刚给大家介绍过Elastic公司宣布:改变 Elasticsearch 和 Kibana 的开源协议,由 Apache 2.0 变更为 SSPL 与 Elastic License而在不久之后,云服务商Logz.io公司就对这一... ...查看全部

来源于公众号“程序猿DD”

前几天刚给大家介绍过Elastic公司宣布:改变 Elasticsearch 和 Kibana 的开源协议,由 Apache 2.0 变更为 SSPL 与 Elastic License

而在不久之后,云服务商Logz.io公司就对这一行为表达了自己的不满。

但是事情还没完,就像最近国内某郑姓女星的瓜层出不穷吃都吃不完一样,开源协议的宫斗剧也是一出接着一出。

当初Elastic公司改变协议的一大目的,就是针对自己的竞争对手AWS(Amazon Web Services——Amazon云服务)。为此Elastic公司的CEO,Shay Banon甚至曾经发文怒斥过AWS的一些行为。

如果说Logz.io公司还只算小打小闹,那么就在前几天,1月21号,AWS 官方做出回应,宣布将基于目前仍为开源状态的 Elasticsearch 和 Kibana( 7.10 版本)创建分支,开源许可证也会继续使用 Apache License 2.0。(和Logz.io公司发文中的意图不谋而合)

为了确保这个分支能够健康的持续发展使用,AWS 也宣称会负责后续的维护工作。

微信图片_20210203173028.png当然,和Logz.io公司发文中直接开怼Elastic不同,AWS更多的采用了隐晦的嘲讽模式(大公司的公关团队就是不一样!)。例如,AWS 声称自己将要创建的这个分支才是真正开源的 Elasticsearch,显然是在暗喻 Elastic 公司即将采用的双许可证方案(SSPL + Elastic License)算不是真正的开源,因为上述两个协议都不是 OSI (Open Source Initiative,开源促进会,批准开源协议的机构) 批准的开源许可证。微信图片_20210203173031.png

不过,AWS类似的事情并不是没有过。早在2019 年AWS就推出一个 Elasticsearch 的发行版——Open Distro for Elasticsearch,当时他们就对外标榜这款采用了 Apache License 2.0协议的产品,是 100% 开源。

AWS做这个申明的时候似乎忘了Amazon 靠着 Elastic 开发出来的东西赚到的钱就比他们自身赚到的还要多,因为这些内容可以跟 Amazon 的其他产品结合得更紧密,让别人使用更方便。

也为了这个Open Distro for Elasticsearch,Elastic 就在当年在加州联邦法院起诉Amazon 侵犯了自己的商标,一次次的矛盾升级之后最终才导致了Elastic痛下决心,进行开源协议改变。

不知道这一次,之前习惯了白嫖的AWS,是否能做出一个更好的开源Elasticsearch,让我们拭目以待!


友情链接