美文网首页React Native开发React Native开发经验集IT梦
【React Native】一款跨平台篮球APP-为爱好而生

【React Native】一款跨平台篮球APP-为爱好而生

作者: hello_bin | 来源:发表于2018-09-16 20:32 被阅读81次

    一 前言

    我本人是一个篮球迷,平时很喜欢打篮球也有关注与篮球相关的资讯,相信NBA对每个篮球迷来讲都是一个再熟悉不过在平台了。篮球是我的爱好,而编程是我的职业,我是一名移动开发者。业余时间想着自己捣鼓个应用,思来想去觉得就做个与篮球相关的吧,一来是自己对这方面稍微了解一些,二来是完成自己的一个念想。

    二 项目背景

    当前了解体育运动赛事资讯的平台很多,例如新浪体育、腾讯体育等,但是这些平台都有一个共同特点:所提供资讯的内容涵盖范围很广,包括篮球、足球、游泳等诸多体育项目,虽然说大型体育资讯平台提供的内容多,但是对于纯篮球迷的用户来说,存在大体量的用户不关心的信息。另外,诸如网页版的体育资讯平台无法及时有效地为用户提供NBA赛事推送提醒。基于此,开发一款只提供篮球相关资讯并且能给用户推送用户感兴趣的球队的赛事信息的跨平台APP,能更好地服务于广大篮球迷。

    应用需要兼容目前最主要的两大移动平台:Android和IOS,而为每端独立开发一套代码,就人力来讲耗时太长,工作量也相对较大,所以就考虑使用跨平台技术来开发,选用由FaceBook开源的React Native,尝试一下非原生模式的开发体验。

    三 技术栈选型

    React Native

    React Native框架旨在使用JavaScript代码构建一个跨平台APP,图3.1是RN底层设计原理框架图。

    图3.1 RN底层设计原理架构图

    JSX可以说是XML的JavaScript语法拓展,在React框架中可以跟JavaScript相互转换。直接操作DOM节点的效率太低,Virtual DOM运用Diff算法更新视图,它实际上是DOM节点在内存中的一种轻型表达方式,不同平台使用各自的渲染引擎来生成UI。在iOS上使用了内置的JavaScriptCore提供JS运行环境,而Android上则是采用Webkit.org官方开源的jsc.so。

    Redux

    APP的状态维护会随着功能的增加而变得艰难,在React中禁止直接操作DOM节点,不然会出现状态变化和异步结果混淆在一起,但是更新State仍然是个棘手的问题。而Redex的集成可以让应用中的数据流更加可控。

    Redux的工作流程如下:当你想要更新状态时,你需要发送一个活动(Action),Action里面写清楚你想要干什么,当你把事情分清楚之后,需要写一个把每个Action和返回的新状态联系起来的函数,这种函数统我们称它为Reducer,它负责给应用中监听状态处返回新的状态。

    Typescript

    熟悉面向对象开发的开发者可以选择TypeScript作为开发语言,因为它具备面向对象语言的特性,React Native提供了插件用于将TypeScript转换成JavaScript。它提供了编译时的类型检查,可以尽可能地避免JavaScript语言运行时可能出现的‘undefined’问题。

    四 开发环境搭建

    ① 使用 Git 进行代码管理;

    ② 本地开发环境搭建,参照 React Natie开发文档

    ③ IDE:Visial Studio Code、Android Studio(本人在应用开发过程仅在Android环境下进行了调试,IOS还没跑过,想要跑IOS在同学需要自己搭建开发环境,可能会一些兼容问题得处理。)

    五 需求分析

    通过网上调查,提取了篮球社区球迷们的意见反馈,我整理出了APP的主要功能需求要点,需求优先级如下表格:

    功能需求 优先级
    获取近日NBA比赛赛程 5级
    查询某场NBA比赛的详细数据 5级
    筛选某天的NBA比赛的场次和数据 4级
    获取最新的NBA球队排名 5级
    查询某支球队的赛季数据、球员数据 5级
    获取NBA新闻资讯 5级
    个人账户中心管理 5级
    社区话题评论 4级
    NBA球员赛季单项数据排行榜 3级
    NBA球员伤病名单 2级
    NBA赛事推送 5级

    了解了用户的实际需求之后,结合需求优先级、现有开发时间、技术实现难度等影响因素,我提取了将投入实际开发的APP的几大功能需求点,分别是:赛况模块、赛事推送、球队模块、新闻模块、社区模块、个人中心模块。图5.1是APP的功能模块图:

    图5.1 功能模块图

    每个模块大致在需求如下:

    赛况模块:赛况模块主要用于展示跟比赛相关的数据,这里维护了一个列表,用户可以看到最近两天的NBA比赛场次,每个场次独立为一个卡片,卡片上可以一目了然地看到比赛对阵双方、比分、当前的比赛状态(未开始、进行中、已结束)。点击卡片响应之后进入相应的比赛详情页。在比赛详情页中,分两个Tab展示对阵双方球队的球员数据,球员数据包括:得分、篮板、助攻、命中率、正负值等。

    赛事推送:赛事推送用于提醒用户赛事信息,篮球迷们一般会有一支自己喜欢的球队,在APP个人中心页面提供了用户选择“我的主队”的功能入口,用户可以选择想要关注的球队提交保存,在每天比赛开始之前,如果有用户所关注球队的比赛,就会提前半个钟发送推送通知用户。

    球队模块:球队模块主要用于展示东西部各支球队的排名情况,这里维护了一个列表,用户可以看到本赛季东西部的球队排名,每个球队独立为一个卡片,卡片上可以一目了然地看到球队本赛季的排名、胜负次数。卡片可以点击,点击响应之后进入球队详情页。在球队详情页中,分两个Tab展示球队赛季基本数据、赛季球员数据。其中,赛季基本数据包括:胜率、投篮命中率、篮板、助攻等;球员数据包括球队中每个现有球员的数据,包括:名称、号码、位置、年龄、身高、体重、赛季场均得分、场均篮板、场均助攻等。

    新闻模块:新闻模块主要用于展示最近的NBA相关资讯,资讯包括球员发表的言论、外界对NBA比赛或者球员的评价等,这里维护了一个列表,用户可以看到新闻,每条新闻独立为一个卡片,卡片上可以一目了然地看到新闻的标题和配图。卡片可以点击,点击响应之后进入新闻详情页,由WebView跳转并展示新闻的原链接,里面包括:新闻的详情、新闻的评论、新闻的视频插播等。

    社区模块:社区模块主要用于展示篮球社区的主流话题,这里维护了一个列表,用户可以看到许多篮球相关的话题,每个话题独立为一个卡片,卡片上有话题的标题、话题的配图。卡片可以点击,点击响应之后进入话题详情页。在话题详情页中,用户可以看到话题的详细内容、用户评论,也可以提交评论。用户评论提交之后,个人账户的积分会累加10分。

    个人中心模块:个人中心模块主要用于维护用户个人资料。页面维护了几个入口:个人资料入口、“我的主队”入口、意见与反馈入口、评价入口、关于入口、退出登录入口。每个入口都可点击,点击响应之后分别进入不同的二级页面。个人资料页面中,用户可以更换自己的昵称、性别、所在地;意见反馈页面,用户可以提交自己对APP的建议或者觉得APP当中设计不合理的地方;评价页面,用户通过选择星星的个数来提交评价,评价的高低与星星的个数成正比关系;关于页面展示APP的相关概览,包括:APP的名称、版本、开发者以及版权。

    六 APP效果图

    1. 登录模块
      登录操作会有用户账号的正则表达式校验,账号和密码的判空操作,如有问题会有相应的错误提示,错误提示如图6.1,6.2所示。
    6.1 登录账号正则表达式检查
    6.2 登录账号正则表达式检查
    1. 推送模块
      推送模块需要前后端合作才能让推送服务准确无误,APP端用户在个人中心进入“我的主队”入口,选择一支自己支持的球队,提交保存,后台接到球队标签之后根据实际赛事情况给用户推送通知。
      推送模块的主要测试点在于:对用户在“我的主队”页面的选择进行检验,由于目前只支持关注一支球队,所以需要对用户的选择结果加以校验并在有误操作的情况下给予提示;推送服务的准确性,对后台推送的赛事信息中的球队进行校验,看是否符合用户所预先选择的标签。推送通知测试情况如图6.3,6.4所示。
    6.3 ‘我的主队’页面
    6.4 通知中心查看赛事推送
    1. 赛况模块
      赛况页面的测试点主要在于赛事信息的准确性、详情页加载的稳定性、赛事搜索页面交互的稳定性和数据的准确性。
      赛事主页的赛事加载采用首次进入全量加载,因为每天的比赛场次基本不会超过15场,所以没有分页加载的必要,赛事搜索页也同样采用全量加载模式。不同的是,搜索页中假设用户输入的日期没有比赛数据,那应该吐司提示“所搜索日期无比赛”,而主页的比赛数据默认加载当前和前一天的数据,假设这两天没有数据,则会一次溯源到离当前日期最近的两天的比赛数据。页面的实现和测试结果如图6.5,6.6,6.7,6.8所示。
    6.5 赛况首页
    6.6 赛事详情页
    6.7 赛事搜索页
    6.8 赛事搜索页'无赛事’
    1. 球队模块
      球队模块的测试点主要在于球队信息和球员信息的准确性,球队主页的球队信息加载同样采用首次进入全量加载,球队详情页中分Tab加载球队基本数据和球员数据,进入详情页前的网络加载会有Spinner提示,网路加载成功后消失。页面测试情况如图6.9,6.10所示。
    6.9 球队首页
    6.10 球队详情页
    1. 新闻模块
      新闻模块的测试点主要在于新闻列表的分页加载,新闻首页采用首次进入加载10条新闻,接下来用户可以点击页面下方的“加载更多”,随即加载第二页的十条数据,依此类推,由于接口限制,分页数据最高可达4页。另一个测试点则是新闻详情页WebView加载网页的稳定性。页面测试情况如图6.11,6.12所示。
    6.11 新闻首页
    6.12 新闻详情页
    1. 社区模块
      社区模块的主要功能有评论提交、评论插入,出于激励机制,每当用户提交一个评论,用户的个人积分会累积10分。测试点主要在于提交评论后评论传输的可靠性、评论列表插入评论的准确性、累积积分数据的准确性。页面测试情况如图6.13,6.14所示。
    6.13 社区详情页提交评论
    6.14 社区详细内容和热门评论
    1. 个人中心模块
      个人中心模块主要测试点在于修改用户个人资料、提交意见反馈、评论APP、退出登录等二级页面的稳定性和可靠性。同时还有一个重要入口:“我的主队”,在此页面中用户可以选择自己支持和关注的一支球队。页面测试情况如图6.15,6.16所示。
    6.15 个人中心首页
    6.16 意见反馈提交页面

    七 总体设计原理

    客户端-服务器交互模式

    APP数据来源于NBA的官方接口和第三方数据平台,客户端需要向接口的服务器发送请求,服务器识别请求并返回数据。当客户端监听到用户触发某个事件时,会发送出对应的Action事件,Action中会有对应的网络请求,由客户端发出一个携带URL、参数等信息的请求,服务器接收到请求之后访问数据库,然后予以响应,请求成果则返回相应的JSON数据,失败则返回错误码。客户端对返回的数据进行解析,并在相应的UI上给予展示。

    基于Redux的客户端数据流

    APP架构采用客户端常用设计模式MVC,基于Redux数据流,其主要流程如图7.1所示,界面UI与数据模型通过中间桥梁Action进行关联,状态的改变导致界面的更新,导致状态改变的事件由活动(Action)发起,在Reducer函数进行处置并返回新的状态。

    7.1 基于Redux在客户端数据流图

    推送服务

    推送服务集成了第三方推送平台极光推送JPush,它供给可视化的web端控制台,可以用于发送推送通知、统计数据。本毕业设计课题中推送服务的主要目的是提前通知用户感兴趣的赛事信息,包括比赛的时间和对阵双方。

    在实现上有两种方案可供选择,一个是本地通知,还有一个是远程通知。

    本地通知的原理是这样的:用户在APP内选择了自己的“主队”之后,客户端将主队的标签以redux缓存保留在本地,一天内用户第一次打开APP的时候就会网络请求后两天的比赛数据,将本地的“主队”标签与网络请求返回的数据集进行比对,提取出与“主队”相关的赛事信息集合,保存在本地。接着,需要JS层与Native层的交互,自定义一个NativeModule接口,接口里面实现一个从JS层获取赛事信息集合的方法,赛事信息集合以方法参数的形式传递过来。最后,使用JPush提供的创建本地通知的API构建通知,设置通知的标题、内容、触发时间。最后,客户端在监听到通知之后就会弹出系统通知框提醒用户相关的赛事信息。

    远程通知的原理是这样的:使用JPush官网提供的服务端SDK在本地集成一个推送服务项目,用户在APP内选择了自己的“主队”之后,客户端将主队的标签以redux缓存保留在本地,与此同时,客户端调用react-native-jpush提供的接口JPushModule.setAlias(alias, successCallback)将标签发送给服务器SDK,后台接收到标签之后会保存起来。每天凌晨零点,推送后台会发送一个访问NBA赛事接口的请求,获取当天的比赛数据集合,然后与“主队”标签做比对,提取出用户关注的球队的赛事信息存放到集合里面。接着,服务器调用JPush服务端SDK提供的接口JPushClient.createSingleSchedule(name,time,PushPayload)设置定时推送通知任务,推送的用户根据就是客户端提交上来的别名,在比赛开始前半个小时会给用户设备发送推送通知,客户端在监听到通知之后就会弹出系统通知框提醒用户相关的赛事信息。

    综合比较两种方案,第二种方案更具可行性。第一种方案受网络因素限制较大,请求比赛数据集合和推送通知都放在客户端进行处理,受用户使用APP情况的影响较大,比如用户今天没有打开APP的话,就无法请求数据,通知推送就无法进行。相比之下,将获取用户关注的球队的赛事信息和推送通知的实现放在服务端来做的话,就可以不受用户操作APP情况的影响,客户端只需要监听通知,这个方案更加准确可靠。

    推送服务方案二的原理图如图7.2所示:

    Android系统上,推送进程会作为服务在后台运行,创建并操持与服务器的长连接,服务端则是调用JPush REST 提供的API来实现自定制的推送服务。

    7.2 推送服务方案二原理图

    九 所遇问题汇总

    QA集合列举如下:

    1. 运行Android工程失败

      Q:
      命令行下运行 react-native run-android 
      ERROR  EPERM: operation not permitted, 
      lstat 'F:\VSCodeWorkSpace\RN\basketballWorkflow\android\app\
      
      A:在AS(已在项目的Android目录下)运行  gradlew clean ,
      重启服务react-native start,
      然后重新run。
      
    2. React Navigaion:导航对象没有根页面

      Q:Please specify at last one route when you configuring the navigator
      
      A:新建 TabNavigator / StackNavigator 对象的时候,不可没有根页面。
      
    3. 更新Typescript

      Q:每次更改文件之后都需要手动执行 tsc,
      待typescript转成javaScript之后,
      才可以执行 react-native run-android
      
      A:开一个终端,运行 tsc -w,
      即可自动检测更改并且转换,
      无需手动执行 tsc
      
    4. 开启Hot Reloading动态更新布局

      Q:调试页面布局的时候,需要手动执行 react-native run-android 或者 摇动手机 Reloading,
      麻烦且耗时
      
      A:摇一摇手机,开启手机的 Enable Hot Reloading
      
    5. React Navigation:如何给React Navigator的headerRight添加监听触摸事件

      Q:如何给React Navigator的headerRight添加监听触摸事件
      
      A:代码例子如下:
      static navigationOptions = ({navigation, screenProps}) => ({  
              headerTitle: '登录',  
              headerLeft:(  
                  <Text  onPress={()=>navigation.state.params.navigatePress()} style={{marginLeft:5, width:30, textAlign:"center"}} >  
                      <Icon  name='ios-arrow-back'size={24} color='white' />  
                  </Text>  
              )  
          });  
        
          _onBackAndroid=()=>{  
              alert('点击headerLeft');  
          }  
            
          componentDidMount(){  
              //在static中使用this方法  
              this.props.navigation.setParams({ navigatePress:this._onBackAndroid })  
          }  
      
    6. 打印日志

      Q:如何在控制台上打印日志(Windows上)
      
      A:打开终端,输入  adb logcat *:S ReactNative:V ReactNativeJS:V
      
    7. 关闭黄色的WarningBox

      Q:
      Warning: isMounted(...) is deprecated in plain JavaScript React classes.
      Instead, make sure to clean up subscriptions and 
      pending requests in componentWillUnmount to prevent memory leaks.
      
      A:
      在index.js中添加忽略这个warning的代码:
      YellowBox.ignoreWarnings(['Warning: GiftedListView:  isMounted is deprecated.'])
      

    十 React Native开发心得

    • React Native “Write once,run everywhere”的设计理念能让开发者以比较小的学习成本来开发出一个跨平台的应用软件,很适合数据流式的App,使用Redux能够很好地管理数据状态;
    • 对于有比较重的需求的软件,比如需要大量使用地图,不建议使用RN开发,一个是性能问题没有原生的好,还有就是第三方地图库对RN的支持不那么完善,很多时候需要自己填坑;
    • 使用RN写UI时,需要关注页面重复渲染的问题,组件的更新在底层使用了diff算法,在Props或者State发生变化时,就会引起组件的重新渲染,当然这也可以通过shouldComponentUpdate生命周期来加以控制,或者让组件继承PureComponent。可能在渲染数据量较小的时候对性能的影响不那么明显,但是还是得养成在写代码过程中关注性能的好习惯;
    • 对于RN能否缩短开发周期,提高开发效率的问题,只能说凡事有利有弊,使用RN开发UI的效率高了,但是在解决一些特定平台问题上面花的时间可能会比较多,因为有些问题只能放在Native去解决,也就意味着需要Android和iOS各自开发一套,然后还要加上Naitve与JS交互的代码。

    后言
    关于APP的介绍这么多了,有什么不对的地方还望多多指教,也欢迎大家关注我(简书/GitHub
    谢谢观看此文。
    欢迎访问 源代码地址

    相关文章

      网友评论

        本文标题:【React Native】一款跨平台篮球APP-为爱好而生

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