当前位置: 首页 > news >正文

wordpress网站防伪查询模板网络口碑营销

wordpress网站防伪查询模板,网络口碑营销,莱阳做网站的,计算机网络网站建设的实训总结背景 美团外卖至今已迅猛发展了六年#xff0c;随着外卖业务量级与日俱增#xff0c;单一的文字和图片已无法满足商家的需求#xff0c;商家迫切需要更丰富的商品描述手段吸引用户#xff0c;增加流量#xff0c;进而提高下单转化率和下单量。商品视频的引入#xff0c;在… 背景 美团外卖至今已迅猛发展了六年随着外卖业务量级与日俱增单一的文字和图片已无法满足商家的需求商家迫切需要更丰富的商品描述手段吸引用户增加流量进而提高下单转化率和下单量。商品视频的引入在一定程度上可以提升商品信息描述丰富度以更加直观的方式为商家引流增加收益。为此商家端引入了视频功能进行了一系列视频功能开发核心功能包含视频处理混音滤镜加水印动画等、视频拍摄、合成等最终效果图如下所示 自视频功能上线后每周视频样本量及使用视频的商家量大幅增加视频录制成功率达99.533%视频处理成功率98.818%音频处理成功率99.959%Crash率稳定在0.1‰稳定性高且可用性强。目前视频功能已在蜜蜂App、闪购业务和商家业务上使用。 对于视频链路的开发我们经历了方案选型、架构设计及优化、业务实践、功能测试、监控运维、更新维护等各个环节核心环节如下图所示。在开发过程中我们遇到了各种技术问题和挑战下文会针对遇到的问题、挑战及其解决方案进行重点阐述。 方案选型 在方案选型时重点对核心流程和视频格式进行选型。我们以功能覆盖度、稳定性及效率、可定制性、成本及开源性做为核心指标从而衡量方案的高可用性和可行性。 1.核心流程选型
 视频开发涉及的核心流程包括播放、录制、合成、裁剪、后期处理编解码、滤镜、混音、动画、水印等。结合商家端业务场景我们有针对性的进行方案调研。重点调研了业界现有方案如阿里的云视频点播方案、腾讯云视频点播方案、大众点评App的UGC方案及其它的一些第三方开源方案等并进行了整体匹配度的对比如下图所示 阿里和腾讯的云视频点播方案比较成熟集成度高且能力丰富稳定性及效率也很高。但两者成本较高需要收费且SDK大小均在15M以上对于我们的业务场景来说有些过于臃肿定制性较弱无法迅速的支持我们做定制性扩展。
 当时的点评App UGC方案基础能力是满足的但因业务场景差异 比如外卖的视频拍摄功能要求在竖屏下保证16:9的视频宽高比这就需要对原有的采集区域进行截取视频段落的裁剪支持不够等业务场景的差异导致了实现方案存在巨大的差异故放弃了点评App UGC方案。其他的一些开源方案比如Grafika等也无法满足要求这里不再一一赘述。
通过技术调研和分析吸取各开源项目的优点并参考点评App UGC、Google CTS方案对核心流程做了最终的方案选型打造一个适合我们业务场景的方案如下表所示 2.视频格式选型
 采用H.264的视频协议H.264的标准成熟稳定普及率高。其最大的优势是具有很高的数据压缩比率在同等图像质量的条件下H.264的压缩比是MPEG-2的2倍以上是MPEG-4的1.52倍。
采用AAC的音频协议AAC是一种专为声音数据设计的文件压缩格式。它采用了全新的算法进行编码是新一代的音频有损压缩技术具有更加高效更具有”性价比“的特点。整体架构 我们整体的架构设计用以满足业务扩展和平台化需要可复用、可扩展且可快速接入。架构采用分层设计基础能力和组件进行下沉业务和视频能力做分离最大化降低业务方的接入成本三方业务只需要接入视频基础SDK直接使用相关能力组件或者工具即可。 整体架构分为四层分别为平台层、核心能力层、基础组件层、业务层。
 平台层依赖系统提供的平台能力比如Camera、OpenGL、MediaCodec和MediaMuxer等也包括引入的平台能力比如ijkplayer播放器、mp4parser
。核心能力层该层提供了视频服务的核心能力包括音视频编解码、音视频的转码引擎、滤镜渲染能力等
。基础能力层暴露了基础组件和能力提供了播放、裁剪、录屏等基础组件和对应的基础工具类并提供了可定制的播放面板可定制的缓存接口等。
业务层包括段落拍摄、自由拍摄、视频空间、拍摄模版预览及加载等。我们的视频能力层对业务层是透明的业务层与能力层隔离并对业务层提供了部分定制化的接口支持这样的设计降低了业务方的接入成本并方便业务方的扩展比如支持蜜蜂App的播放面板定制还支持缓存策略、编解码策略的可定制。整体设计如下图所示 实践经验 在视频开发实践中因业务场景的复杂性我们遇到了多种问题和挑战。下面以核心功能为基点围绕各功能遇到的问题做详细介绍。 视频播放 播放器是视频播放基础。针对播放器我们进行了一系列的方案调研和选择。在此环节遇到的挑战如下 1.兼容性问题 2.缓存问题 针对兼容性问题Android有原生的MediaPlayer但其版本兼容问题偏多且支持格式有限而我们需要支持播放本地视频本地视频格式又无法控制故该方案被舍弃。ijkplayer基于FFmpeg与MediaPlayer相比优点比较突出具备跨平台能力支持Android与iOS提供了类似MediaPlayer的API可兼容不同版本可实现软硬解码自由切换拥有FFmpeg的能力支持多种流媒体协议。基于上述原因我们最终决定选用ijkplayer。 但紧接着我们又发现ijkplayer本身不支持边缓存边播放频繁的加载视频导致耗费大量的流量且在弱网或者3G网络下很容易导致播放卡顿所以这里就衍生出了缓存的问题。 针对缓存问题我们引入AndroidVideoCache的技术方案利用本地的代理去请求数据先本地保存文件缓存客户端通过Socket读取本地的文件缓存进行视频播放这样就做到了边播放边缓存的策略流程如下图 此外我们还对AndroidVideoCache做了一些技术改造 优化缓存策略。针对缓存策略的单一性支持有限的最大文件数和文件大小问题我们调整为由业务方可以动态定制缓存策略解决内存泄露隐患。对其页面退出时请求不关闭会导致的内存泄露我们为其添加了完整的生命周期监控解决了内存泄露问题。视频录制 在视频拍摄的时候最为常用的方式是采用MediaRecorderCamera技术采集摄像头可见区域。但因我们的业务场景要求视频采集的时候只录制采集区域的部分区域且比例保持宽高比16:9在保证预览图像不拉伸的情况下只能对完整的采集区域做裁剪这无形增加了开发难度和挑战。通过大量的资料分析我们重点调研了有两种方案 CameraAudioRecordMediaCodecSurfaceMediaRecorderMediaCodec方案1需要Camera采集YUV帧进行截取采集最后再将YUV帧和PCM帧进行编码生成mp4文件虽然其效率高但存在不可把控的风险。 方案2综合评估后是改造风险最小的。
综合成本和风险考量我们保守的采用了方案2该方案是对裁剪区域进行坐标换算如果用前置摄像头拍摄录制视频会出现预览画面和录制的视频是镜像的问题需要处理。当录制完视频后生成了mp4文件用MediaCodec对其编码在编码阶段再利用OpenGL做内容区域的裁剪来实现。但该方案又引发了如下挑战 1对焦问题 因我们对采集区域做了裁剪引发了点触对焦问题。比如用户点击了相机预览画面正常情况下会触发相机的对焦动作但是用户的点击区域只是预览画面的部分区域这就导致了相机的对焦区域错乱不能正常进行对焦。后期经过问题排查对点触区域再次进行相应的坐标变换最终得到正确的对焦区域。 2兼容适配 我们的视频录制利用MediaRecorder在获取配置信息时由于Android碎片化问题不同的设备支持的配置信息不同所以就会出现设备适配问题。 // VIVO Y66 模版拍摄时候播放某些有问题的视频文件的同时去录制视频会导致MediaServer挂掉的问题// 发现将1080P尺寸的配置降低到720P即可避免此问题// 但是720P尺寸的配置下又存在绿边问题因此再降到480if(isVIVOY66() mMediaServerDied) {return getCamcorderProfile(CamcorderProfile.QUALITY_480P);}//SM-C9000,在1280 x 720 分辨率时有一条绿边。网上有种说法是GPU对数据进行了优化使得GPU产生的图像分辨率//和常规分辨率存在微小差异造成图像色彩混乱修复后存在绿边问题。//测试发现降低分辨率或者升高分辨率都可以绕开这个问题。if (VideoAdapt.MODEL_SM_C9000.equals(Build.MODEL)) {return getCamcorderProfile(CamcorderProfile.QUALITY_HIGH);}// 优先选择 1080 P的配置CamcorderProfile camcorderProfile getCamcorderProfile(CamcorderProfile.QUALITY_1080P);if (camcorderProfile null) {camcorderProfile getCamcorderProfile(CamcorderProfile.QUALITY_720P);}// 某些机型上这个 QUALITY_HIGH 有点问题可能通过这个参数拿到的配置是1080p所以这里也可能拿不到if (camcorderProfile null) {camcorderProfile getCamcorderProfile(CamcorderProfile.QUALITY_HIGH);}// 兜底if (camcorderProfile null) {camcorderProfile getCamcorderProfile(CamcorderProfile.QUALITY_480P);}视频合成 我们的视频拍摄有段落拍摄这种场景商家可根据事先下载的模板进行分段拍摄最后会对每一段的视频做拼接拼接成一个完整的mp4文件。mp4由若干个Box组成所有数据都封装在Box中且Box可再包含Box的被称为Container Box。mp4中Track表示一个视频或音频序列是Sample的集合而Sample又可分为Video Smaple和Audio Sample。Video Smaple代表一帧或一组连续视频帧Audio Sample即为一段连续的压缩音频数据。详见mp4文件结构。 基于上面的业务场景需要视频合成的基础能力我们采用mp4parser技术实现也可用FFmpeg等其他手段。mp4parser在拼接视频时先将视频的音轨和视频轨进行分离然后进行视频和音频轨的追加最终将合成后的视频轨和音频轨放入容器里这里的容器就是mp4的Box。采用mp4parser技术简单高效API设计简洁清晰满足需求。 但我们发现某些被编码或处理过的mp4文件可能会存在特殊的Box并且mp4parser是不支持的。经过源码分析和原因推导发现当遇到这种特殊格式的Box时会申请分配一个比较大的空间用来存放数据很容易造成OOM内存溢出见下图所示。于是我们对这种拼接场景下做了有效规避仅在段落拍摄下使用mp4parser的拼接功能保证我们处理过的文件不会包含这种特殊的Box。 视频裁剪 我们刚开始采用mp4parser技术完成视频裁剪在实践中发现其精度误差存在很大的问题甚至会影响正常的业务需求。比如我们禁止裁剪出3s以下的视频但是由于mp4parser产生的精度误差导致4-5s的视频很容易裁剪出少于3s的视频。究其原因mp4parser只能在关键帧又称I帧在视频编码中是一种自带全部信息的独立帧进行切割这样就可能存在一些问题。比如在视频截取的起始时间位置并不是关键帧因此会造成误差无法保证精度而且是秒级误差。以下为mp4parser裁剪的关键代码 public static double correctTimeToSyncSample(Track track, double cutHere, boolean next) {double[] timeOfSyncSamples new double[track.getSyncSamples().length];long currentSample 0;double currentTime 0;for (int i 0; i track.getSampleDurations().length; i) {long delta track.getSampleDurations()[i];int index Arrays.binarySearch(track.getSyncSamples(), currentSample 1);if (index 0) {timeOfSyncSamples[index] currentTime;}currentTime ((double) delta / (double) track.getTrackMetaData().getTimescale());currentSample;}double previous 0;for (double timeOfSyncSample : timeOfSyncSamples) {if (timeOfSyncSample cutHere) {if (next) {return timeOfSyncSample;} else {return previous;}}previous timeOfSyncSample;}return timeOfSyncSamples[timeOfSyncSamples.length - 1]; } 为了解决精度问题我们废弃了mp4parser采用MediaCodec的方案虽然该方案会增加复杂度但是误差精度大大降低。 方案具体实施如下先获得目标时间的上一帧信息对视频解码然后根据起始时间和截取时长进行切割最后将裁剪后的音视频信息进行压缩编码再封装进mp4容器中这样我们的裁剪精度从秒级误差降低到微秒级误差大大提高了容错率。 视频处理 视频处理是整个视频能力最核心的部分会涉及硬编解码遵循OpenMAX框架、OpenGL、音频处理等相关能力。
 下图是视频处理的核心流程会先将音视频做分离并行处理音视频的编解码并加入特效处理最后合成进一个mp4文件中。 在实践过程中我们遇到了一些需要特别注意的问题比如开发时遇到的坑严重的兼容性问题包括硬件兼容性和系统版本兼容性问题等。下面重点讲几个有代表性的问题。 1.偶数宽高的编解码器 视频经过编码后输出特定宽高的视频文件时出现了如下错误信息里仅提示了Colorformat错误具体如下 查阅大量资料也没能解释清楚这个异常的存在。基于日志错误信息并通过系统源码定位也只是发现了是和设置的参数不兼容导致的。经过反复的试错最后确认是部分编解码器只支持偶数的视频宽高所以我们对视频的宽高做了偶数限制。引起该问题的核心代码如下 status_t ACodec::setupVideoEncoder(const char *mime, const spAMessage msg,spAMessage outputFormat, spAMessage inputFormat) {if (!msg-findInt32(color-format, tmp)) {return INVALID_OPERATION;}OMX_COLOR_FORMATTYPE colorFormat static_castOMX_COLOR_FORMATTYPE(tmp);status_t err setVideoPortFormatType(kPortIndexInput, OMX_VIDEO_CodingUnused, colorFormat);if (err ! OK) {ALOGE([%s] does not support color format %d,mComponentName.c_str(), colorFormat);return err;}....... } status_t ACodec::setVideoPortFormatType(OMX_U32 portIndex,OMX_VIDEO_CODINGTYPE compressionFormat,OMX_COLOR_FORMATTYPE colorFormat,bool usingNativeBuffers) {......for (OMX_U32 index 0; index kMaxIndicesToCheck; index) {format.nIndex index;status_t err mOMX-getParameter(mNode, OMX_IndexParamVideoPortFormat,format, sizeof(format));if (err ! OK) {return err;}...... }2. 颜色格式 我们在处理视频帧的时候一开始获得的是从Camera读取到的基本的YUV格式数据如果给编码器设置YUV帧格式需要考虑YUV的颜色格式。这是因为YUV根据其采样比例UV分量的排列顺序有很多种不同的颜色格式Android也支持不同的YUV格式如果颜色格式不对会导致花屏等问题。 3. 16位对齐 这也是硬编码中老生常谈的问题了因为H264编码需要16*16的编码块大小。如果一开始设置输出的视频宽高没有进行16字节对齐在某些设备华为三星等就会出现绿边或者花屏。 4. 二次渲染 4.1 视频旋转 在最后的视频处理阶段用户可以实时的看到加滤镜后的视频效果。这就需要对原始的视频帧进行二次处理然后在播放器的Surface上渲染。首先我们需要OpenGL 的渲染环境通过OpenGL的固有流程创建渲染环境完成后就可以对视频的帧数据进行二次处理了。通过SurfaceTexture的updateTexImage接口可将视频流中最新的帧数据更新到对应的GL纹理再操作GL纹理进行滤镜、动画等处理。在处理视频帧数据的时候首先遇到的是角度问题。在正常播放下不利用OpenGL处理情况下通过设置TextureView的角度和视频的角度做转换就可以解决但是加了滤镜后这一方案就失效了。原因是视频的原始数据经过纹理处理再渲染到Surface上单纯设置TextureView的角度就失效了解决方案就是对OpenGL传入的纹理坐标做相应的旋转依据视频的本身的角度。 4.2 渲染停滞 视频在二次渲染后会出现偶现的画面停滞现象主要是SurfaceTexture的OnFrameAvailableListener不返回数据了。该问题的根本原因是GPU的渲染和视频帧的读取不同步进而导致SurfaceTexture的底层核心BufferQueue读取Buffer出了问题。下面我们通过BufferQueue的机制和核心源码深入研究下 首先从二次渲染的工作流程入手。从图像流来自Camera预览、视频解码、GL绘制场景等中获得帧数据此时OnFrameAvailableListener会回调。再调用updateTexImage()会根据内容流中最近的图像更新SurfaceTexture对应的GL纹理对象。我们再对纹理对象做处理比如添加滤镜等效果。SurfaceTexture底层核心管理者是BufferQueue本身基于生产者消费者模式。 BufferQueue管理的Buffer状态分为FREEDEQUEUEDQUEUEDACQUIREDSHARED。当Producer需要填充数据时需要先Dequeue一个Free状态的Buffer此时Buffer的状态为DEQUEUED成功后持有者为Producer。随后Producer填充数据完毕后进行Queue操作Buffer状态流转为QUEUED且Owner变为BufferQueue同时会回调BufferQueue持有的ConsumerListener的onFrameAvailable进而通知Consumer可对数据进行二次处理了。Consumer先通过Acquire操作获取处于QUEUED状态的Buffer此时Owner为Consumer。当Consumer消费完Buffer后会执行Release该Buffer会流转回BufferQueue以便重用。BufferQueue核心数据为GraphicBuffer而GraphicBuffer会根据场景、申请的内存大小、申请方式等的不同而有所不同。 SurfaceTexture的核心流程如下图 通过上图可知我们的Producer是Video填充视频帧后再对纹理进行特效处理滤镜等最后再渲染出来。前面我们分析了BufferQueue的工作流程但是在Producer要填充数据执行dequeueBuffer操作时如果有Buffer已经QUEUED且申请的dequeuedCount大于mMaxDequeuedBufferCount就不会再继续申请Free Buffer了Producer就无法DequeueBuffer也就导致onFrameAvailable无法最终调用核心源码如下 status_t BufferQueueProducer::dequeueBuffer(int *outSlot,spandroid::Fence *outFence, uint32_t width, uint32_t height,PixelFormat format, uint32_t usage,FrameEventHistoryDelta* outTimestamps) {......int found BufferItem::INVALID_BUFFER_SLOT;while (found BufferItem::INVALID_BUFFER_SLOT) {status_t status waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, found);if (status ! NO_ERROR) {return status;}}...... } status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,int*found) const{......while (tryAgain) {int dequeuedCount 0;int acquiredCount 0;for (int s : mCore - mActiveBuffers) {if (mSlots[s].mBufferState.isDequeued()) {dequeuedCount;}if (mSlots[s].mBufferState.isAcquired()) {acquiredCount;}}// Producers are not allowed to dequeue more than// mMaxDequeuedBufferCount buffers.// This check is only done if a buffer has already been queuedif (mCore - mBufferHasBeenQueued dequeuedCount mCore - mMaxDequeuedBufferCount) {BQ_LOGE(%s: attempting to exceed the max dequeued buffer count (%d), callerString, mCore - mMaxDequeuedBufferCount);return INVALID_OPERATION;}}.......}5. 码流适配 视频的监控体系发现Android 9.0的系统出现大量的编解码失败问题错误信息都是相同的。在MediaCodec的Configure时候出异常了主要原因是我们强制使用了CQ码流Android 9.0以前并无问题但9.0及以后对CQ码流增加了新的校验机制而我们没有适配。核心流程代码如下 status_t ACodec::configureCodec(const char *mime, const spAMessage msg) {.......if (encoder) {if (mIsVideo || mIsImage) {if (!findVideoBitrateControlInfo(msg, bitrateMode, bitrate, quality)) {return INVALID_OPERATION;}} else if (strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC) !msg-findInt32(bitrate, bitrate)) {return INVALID_OPERATION;}}....... } static bool findVideoBitrateControlInfo(const spAMessage msg,OMX_VIDEO_CONTROLRATETYPE *mode, int32_t *bitrate, int32_t *quality) {*mode getVideoBitrateMode(msg);bool isCQ (*mode OMX_Video_ControlRateConstantQuality);return (!isCQ msg-findInt32(bitrate, bitrate))|| (isCQ msg-findInt32(quality, quality)); } 9.0前并无对CQ码流的强校验如果不支持该码流也会使用默认支持的码流 static OMX_VIDEO_CONTROLRATETYPE getBitrateMode(const spAMessage msg) {int32_t tmp;if (!msg-findInt32(bitrate-mode, tmp)) {return OMX_Video_ControlRateVariable;}return static_castOMX_VIDEO_CONTROLRATETYPE(tmp); }关于码流还有个问题就是如果通过系统的接口isBitrateModeSupportedint mode判断是否支持该码流可能会出现误判究其原因是framework层写死了该返回值而并没有从硬件层或从media_codecs.xml去获取该值。关于码流各硬件厂商支持的差异性可能谷歌也认为码流的兼容性太碎片化不建议用非默认的码流。 6. 音频处理 音频处理还括对音频的混音消声等操作。在混音操作的时候还要注意音频文件的单声道转换等问题。 其实视频问题总结起来大部分是都会牵扯到编解码尤其是使用硬编码需要大量的适配工作以上也只是部分问题碎片化还是很严峻的所以就需要兜底容错方案比如加入软编。 线上监控 视频功能引入了埋点日志链路监控等技术手段进行线上的监控我们可以针对监控结果进行降级或维护更新。埋点更多的是产品维度的数据收集日志是辅助定位问题的而链路监控则可以做到监控预警。我们加了拍摄流程音视频处理视频上传流程的全链路监控整个链路如果任何一个节点出问题都认为是整个链路的失败若失败次数超过阈值就会通过大象或邮件进行报警我们在适配Andorid 9.0码流问题时最早发现也是由于链路监控的预警。所有全链路的成功率目标值均为98%若成功率低于92%的目标阈值就会触发报警我们会根据报警的信息和日志定位分析该异常的影响范围再根据影响范围确定是否热修复或者降级。如下以拍摄流程为例其链路各核心节点的监控 拍摄流程全链路如下图各关键节点监控 容灾降级 视频功能目前只支持粗粒度的降级策略。我们在视频入口处做了开关控制关掉后所有的视频功能都无法使用。我们通过线上监控到视频的稳定性和成功率在特定机型无法保证导致影响用户正常的使用商家端App我们支持针对特定设备做降级。后续我们可以做更细粒度的降级策略比如根据P0级功能做降级或者编解码策略的降级等 维护更新 视频功能上线后经历了几个稳定的版本保持着较高的成功率但近期收到了sniffer的邮件报警发现视频处理链路的失败次数明显增多通过sniffer收集的信息发现大部分都是Android 9.0的问题也就是上面讲的Android 9.0码流适配的问题我们在商家端5.2版本进行了修复该问题解决后我们的视频处理链路成功率也恢复到了98%以上。 总结和规划 视频功能上线后稳定性、内存、CPU等一些相关指标数据比较理想我们建设的视频监控体系也支撑着视频核心业务的监控一些异常报警也让我们及时发现问题并迅速对异常进行维护更新但视频技术栈也是远比本文介绍的要庞大怎么提高秒播率怎么提高编解码效率还有硬编解码过程中可能造成的花屏绿边等问题都是挑战需要更深入的研究解决。 未来我们会继续致力于提高视频处理的兼容性和效率优化现有流程我们会对音频和视频处理合并处理也会引入软编和自定义编解码算法。 美团外卖大前端团队将来也会继续致力于提高用户的体验并且会将在实践过程中遇到的问题进行总结沉底技术积极的和大家分享如果你也对视频感兴趣欢迎加入我们。 参考资料 Android开发者官网Google CTSGrafikaBufferQueue原理介绍MediaCodec原理微信Android 视频编码爬过的坑mp4文件结构AndroidVideoCache 代理策略ijkplayermp4parserGPUImage作者简介 金辉、李琼美团外卖商家终端研发工程师。 招聘信息 美团外卖商家终端研发团队的主要职责是为商家提供稳定可靠的生产经营工具在保障稳定的需求迭代的基础之上持续优化APP、PC和H5的性能和用户体验并不断优化提升团队的研发效率。团队主要负责的业务主要包括外卖订单、商品管理、门店装修、服务市场、门店运营、三方会话、蓝牙打印、自动接单、视频、语音和实时消息触达等基础业务支撑整个外卖链路的高可用性及稳定发展。 团队通过架构演进及平台化体系化建设有效支撑业务发展提升了业务的可靠性和安全性通过大规模落地跨平台和动态化技术加快了业务迭代效率帮助产品PM加快产品方案的落地及上线通过监控容灾体系建设有效保障业务的高可用性和稳定性通过性能优化建设保证APP的流畅性和良好用户体验。团队开发的技术栈包括Android、iOS、React、Flutter和React Native。 美团外卖商家端研发团队长期招聘Android、iOS、和前端工程师欢迎有兴趣的同学投简历至techmeituan.com注明美团外卖商家端
http://www.sadfv.cn/news/412461/

相关文章:

  • 某俄文网站wordpress主题开发文档
  • 泸州网站建设报价微信营销要怎么做
  • 网站需要更新的频率泉州网站建设哪里优惠
  • 网站开发服务器框架申请建设单位门户网站的请示
  • 太原网站seo中国工程机械网官网
  • 山东省建设机械协会网站校园视频网站建设
  • 传媒公司网站建设策划上海传媒公司总裁李闪闪
  • 互联网app网站建设方案模板深圳自适应网站开发多少钱
  • 网站优化计划书学校网站建设的必要性
  • 深圳网站创建公司河北省住建和城乡建设厅网站首页
  • 网站幻灯片尺寸设置环球贸易网的服务内容
  • 郑州建站模板网站开发期末作品代码和数据库运行好大全
  • 滁州网站建设联系方式假发网站建设
  • 张家界建设网站制作一小时赚8000元的游戏
  • 燕郊做网站的公司做网站放视频
  • 漂亮的手机网站模板python在线编程视频
  • 网站开发一般用什么开发语言沈阳 网站制作报价
  • 网站开发 经济可行性织梦网站做404页面
  • idea做网站天猫网站建设的意义
  • 魔兽7.2国内做插件网站营销型企业网站系统
  • 免费的网站程序免费设计logo的app
  • 购房网站系统建设方案用php做网站视频
  • 安庆跨境电商建站哪家好全案营销策划
  • 网站建设江阴基于wed的网站开发
  • 三亚做网站哪家好做网站域名公司
  • 网站建设中的推广工作宁德古田建设局网站
  • 网页设计企业宣传网站响应式
  • 顾客评价网站网站伪静态规则
  • 网站注册系统交易网站模板
  • 境外网站 备案国内比较好的wordpress主题