RN开发填坑之旅

大概是2017年底接触的RN,当时项目开发中遇到很多问题,都是自己一步一个坑走过来的。看了下当时的笔记,觉得还是在这里记录下,防丢失。

React-native APP 开始

  1. App Store下载Xcode并安装(about one hour)

  2. 下载并安装Android studio:https://developer.android.com/studio/index.html(需翻墙,take too long)

  3. npm install -g react-native-cli

  4. react-native init MyApp(最新版可能下载失败导致无法成功run ios,所以用下面的version)

    react-native init MyApp --version 0.44.3

iOS模拟器调试

  1. cd 进入MyApp目录下(你的项目目录)

  2. react-native run-ios

  3. 若报错:xcrun: error: unable to find utility "instruments", not a developer tool or in PATH

    解决:sudo xcode-select -s /Applications/Xcode.app/Contents/Developer/

  4. 若模拟器爆红:No bundle URL present

    解决1:在模拟器运行期间 项目目录下执行npm install

    解决2:检查翻墙的代理,由全局模式改为自动模式即可

iOS真机调试

  1. 打开Xcode

  2. 绑定Apple ID:Xcode 》preferences 》accounts

  3. 选中左侧project根目录,点击右侧General配置

  4. identity 》Bundle identifier 输入唯一标识(保证唯一即可)

  5. Signing 》Team 选中刚刚绑定的Apple ID对应的team

  6. 点击左上角run 按钮右侧运行设备选项,选中USB已连接的你的设备

  7. run

  8. 过程中出问题按照提示对设备进行授权配置

  9. 若build时就出错,尝试重启Xcode,再run

  10. 若connect server error:查看手机电脑wiffi是否一致,若不一致,停掉服务重新run

  11. 若报错The application does not have a valid signature.clean下重跑

android调试

  1. cd进入MyApp目录

  2. react-native run-android

  3. 若报错:Error watching file for changes: EMFILE

    解决办法:watchman出错,卸载并重装

    brew uninstall --force watchman

    rm -rf/usr/local/var/run/watchman/

    brew install watchman

  4. 错误信息不明时可打开android studio查看详情

  5. 若gradle的问题:可能因为android studio 的gradle没加载成功,修改gradle-wrapper.properties文件内url为其他版本,例:

    https://services.gradle.org/distributions/gradle-3.3-all.zip

    或改成本地地址在setting内加以配置

  6. 可通过http://localhost:8081/index.android.bundle?platform=android去验证服务是否成功开启

  7. 报错could not connect development server:(坑!)

    (1). android studio debug运行模式,

    (2). 打开命令行,cd到当前目录,react-native start

    (3). 真机或模拟器reload,成功与否

    (4). 若失败:adb reverse tcp:8081 tcp:8081,reload(5). 若command adb not found:"adb"不是内部命令和sudo: adb: command not found

  1. 真机adb无响应:(可能因为其他应用占用adb的5037端口)

    解决:netstat -aon|findstr “5037” 找到占用端口的进程PID,​ 打开任务管理器,杀掉对应进程。​ 重新run

react-native学习指南

参考:给所有开发者的React Native详细入门指南

引用antd-mobile的坑

  1. 对于莫名其妙的问题,确保自己antd-mobile的版本不要太低,坑

  2. 对于找不到module的问题,请用yarn安装,cnpm安装可能会漏掉一些依赖

  3. 对于antd-mobile not defined 的错误,确保安装了react-dom,antd-mobile,babel-plugin-import,并且修改.babelrc 文件,例:

{  
 "plugins": [["import", { "libraryName": "antd-mobile" }]],    "presets": ["react-native"]
}

在react-native使用Icon

  1. 使用antd-mobile的Icon

    RN 版本由于 Icon 无法做纯 UI,需要 native 支持

    • 下载 https://at.alicdn.com/t/font_r5u29ls31bgldi.ttf 重命名为 anticon.ttf

    • 打开 iOS 项目 info.plist 文件,添加 Fonts provided by application,指定一个 item 的值为 anticon.ttf, 将 anticon.ttf 拖进项目;

    • Android 项目将 anticon.ttf 放在 android/app/src/main/assets/fonts/ 目录下;

    使用方式:

内置的几个图标: <Icon type="check" size="md" color="red" />
自定义图标:<Icon type={'\ue601'} size={55} /> (具体参看 demo)

自定义图标:<Icon type={'\ue601'} size={55} /> (具体参看 demo)</pre>

  1. 使用react-native-vector-icons

    参考react-native-vector-icons的简单使用

    Icon选用参考:http://fontawesome.io/icons/

若出现搜不到的问题,尝试卸载APP重启

native-echarts

  1. React Native使用百度Echarts显示图表的示例代码

  2. Android 上图表有时不显示问题

    原因:图形渲染支持的不好?

    解决:隐藏包含echart的div,数据填充渲染结束后显示div,中间要有一定时间的延迟,比如100ms

android打包

  1. 根据RN官网推荐方式打包

  2. 若类似错:Could not find com.android.tools.build:gradle:3.0.0.

    可能:自己android studio版本不是3.0.0,换成对应版本

    或者:android/build.gradle下

buildscript {
    repositories {
        ...
        google()
    }
}
  1. 若报错:Could not get unknown property 'MYAPP_RELEASE_STORE_FILE'

    原因:将如下代码加入到android/gradle.properties, **改为密钥

MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
MYAPP_RELEASE_KEY_ALIAS=my-key-alias
MYAPP_RELEASE_STORE_PASSWORD=****
MYAPP_RELEASE_KEY_PASSWORD=****
  1. 项目中用到react-native-echarts,在android打包后无法显示图表:

    原因:release版本只能使用uri加载资源(???)

    解决:

    1. 把node_modules/native-echarts/src/components/Echarts/tpl.html文件复制一份到android/app/src/main/assets文件里

    2. 修改node_modules/native-echarts/src/components/Echarts/index.js:source={require('./tpl.html')}改为source={{uri:'file:///android_asset/tpl.html'}}

    3. 打包后记得改回来,不然ios无法正常显示图表

  2. 修改版本信息:

    android在android/app/build.gradle文件下修改

    其中versionCode一般是整数,上传appstore时,每次都需比上次数字要大,否则不予覆盖上一版本

    versionName用于在app上显示版本信息,供自己或用户查看

defaultConfig{
  versionCode 1
  versionName "1.0"
}

IOS打包

  1. 在Xcode中选择Product -> Scheme -> Edit Scheme (cmd + <),然后选择Run选项卡,将Build Configuration设置为release

  2. 在ios中用http请求需做配置,参照让iOS项目允许使用http协议请求

  3. run,若想调试,将Build Configuration重新设置为debug

  4. 一键打包:React-Native中iOS一键打包发布脚本

  5. 设置应用图标和闪屏图片react native ios打包到真机

  6. 若出现其他手机无法run release版本,报错:

can't link with a main executable file '/Users/liujinling/Library/Developer/Xcode/DerivedData/gngcApp-glzeunbnyelbpmcrehcygunmtjfq/Build/Products/Release-iphoneos/gngcApp.app/gngcApp' for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)

解决:
product ->schema-> edit ->schema-> run 选择release buildxxxTests 只勾选Testbuild中xxx 勾选全部

  1. 账号下手机连接数量达上限,无法使用其他手机调试或安装:

    原因:免费的账号连接设备数应该是3个左右,想连接更多的测试机,升级到收费账号,可连100个设备

    解决:1. 申请企业收费开发者账号

    ​ 2. General/signing/Team:添加一个新的account

  2. 安装release版时报错:Could not write to the device,或A valid provisioning profile for this executable was not found.:

    原因:我这里因为切换team(开发者账号)导致

    解决:Xcode上方导航栏product下clean操作,重新run

Mac 下gradle配置

android studio 下载gradle极慢,所以下载到本地自己配置

  1. 下载所需版本:http://services.gradle.org/distributions/ (例:gradle-4.1-all)

  2. 命令open .gradle 打开finder,

  3. 进入wrapper/dists/gradle-4.1-all/(njsjdscn),删掉目录下所有

  4. 将下载的gradle-4.1-all.zip拉进来,重启android studio

记一次重大填坑现场

在android和ios真机+模拟器run成功n次,双机打包均跑成功后,再次android真机调试时,突然的gradle构建失败!!!WTF

诡异1:android打包时按照react-native官网配置了一些文件,今天打开代码,发现一会这里多了个‘g’,一会那里classpath被删掉,还有其他的属性名缺了一半,连gradle.zip后面紧跟了个’android‘……细思极恐

诡异2:react-native-linear-gradient库突然无法正确引入?错误提示:com.facebook.react:react-native:+

诡异3:android/app/build.gradle文件找不到com.facebook.react:react-native:+

解决

  1. 在android studio 报错处跟踪进react-native-linear-gradient,添加一块代码,既然gradle找不到com.facebook.react:react-native:+,我们就告诉他怎么找
repositories {
    jcenter()
}
  1. 在android/app/build.gradle添加如下代码
allprojects {
    repositories {
        jcenter()
        mavenCentral()
        mavenLocal()
        maven {
            // All of React Native (JS, Android binaries) is installed from npm
            url "$rootDir/../node_modules/react-native/android"
        }
    }
}

url "$rootDir/../node_modules/react-native/android"报错,将其改为url "$rootDir/node_modules/react-native/android"。应该是通过yarn安装的react-native使用前者,通过npm安装的使用后者

莫名其妙的坑,踩了一下午,燥

又一次重重大填坑现场

RN Android 文件预览

  1. 利用react-native-doc-viewer

    *注意注释部分

const handlePress = (name,id) => {
  const nameArr = name.split('.');
  const type = nameArr[nameArr.length - 1];
  //Interface.downloadUrl + id是文件的下载地址
  const downloadUrl = Interface.downloadUrl + id + '.' + type;
  if (Platform.OS === 'ios') {
    //IOS(成功预览)
    OpenFile.openDoc([{
      url: downloadUrl,
      //此处url后缀必须带文件type(例:.doc)
      //原因:ios配置没有fileType,需靠url后缀识别文件类型
      fileNameOptional: name
      //ios的fileNameOptional取值中文是ok的
    }], (error, url) => {
      if (error) {
        console.error(error);
      } else {
        console.log(url, '成功')
      }
    })
  } else {
    //Android(除图片外,其他无效,打不开文件)
    OpenFile.openDoc([{
      url: Interface.downloadUrl + id,
      //此处url直接为下载地址,无需特意加类型后缀
      fileName: name,
      //Android的fileName取值中文报错
      cache:false,
      fileType:type
    }], (error, url) => {
      if (error) {
        console.error(error);
      } else {
        console.log(url, '成功')
      }
    })
    }
  }
  1. 辅助react-native-fs
//Android
const SavePath = RNFS.DocumentDirectoryPath;
//const SavePath = RNFS.ExternalDirectoryPath;
//const SavePath = RNFS.ExternalStorageDirectoryPath;

//当配合react-native-doc-viewer,以上三个路径均测试,无法打开文件
//当配合原生模块,使用第二个

//const SavePath = RNFS.MainBundlePath //ios的存储路径
const options = {
  fromUrl: downloadUrl,
  //加不加类型后缀都ok
  toFile: `${SavePath}/${name}`,
};

RNFS.downloadFile(options).promise.then(res => {
  console.log(res, 'res')
  //配合react-native-doc-viewer(无效)
  OpenFile.openDoc([{
      url: `file://${SavePath}/${name}`,
      //此处url为系统内部路径,前面需加‘file://’
      fileName: name,
      //Android的fileName取值中文报错
      cache:false,
      fileType:type
    }], (error, url) => {
      if (error) {
        console.error(error);
      } else {
        console.log(url, '成功')
      }
    })
  //配合原生模块(成功)
  NativeModules.OpenFileModule.show(`${SavePath}/${name}`)
        
}).catch(err => {
  console.log(err, 'err')
})
  1. react-native-fs加原生模块实现
//任意位置新建一个类(java文件)
package com.reactNativeModules;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.webkit.MimeTypeMap;
import android.widget.Toast;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

import java.io.File;
import java.util.Locale;
public OpenFileModule(ReactApplicationContext reactContext){
   super(reactContext);
 }

 @Override
 public String getName(){
   return "OpenFileModule";
 }
 //getName为必需

 @ReactMethod
 private void show(final String filePath)
 {
   String ext = filePath.substring(filePath.lastIndexOf('.')).toLowerCase(Locale.US);
   try
     {
       MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
       String temp = ext.substring(1);
       String mime = mimeTypeMap.getMimeTypeFromExtension(temp);
       Intent intent = new Intent();
                  intent.setAction(android.content.Intent.ACTION_VIEW);
       File file = new File(filePath);
       intent.setDataAndType(Uri.fromFile(file), mime);
//这里原本:startActivity(intent); 
//但由于react调原生方法,不存在原生activity,报错,使用下面两句代替
       Activity currentActivity = getCurrentActivity();              currentActivity.startActivity(intent);
     }
   catch (Exception e)
     {
       e.printStackTrace();
       Toast.makeText(getReactApplicationContext(), "无法打开后缀名为." + ext + "的文件!",
       Toast.LENGTH_LONG).show();
     }
   }
//任意位置定义一个包(java文件)
   package com.reactNativeModules;

   import com.facebook.react.ReactPackage;
   import com.facebook.react.bridge.JavaScriptModule;
   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;

   /**
    * Created by liujinling on 2018/1/23.
    */

   public class OpenFilePackage implements ReactPackage{
       @Override
       public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
           return Collections.emptyList();
       }

       @Override
       public List<NativeModule> createNativeModules(
               ReactApplicationContext reactContext) {
           List<NativeModule> modules = new ArrayList<>();
         
        //OpenFileModule为上文新建的类名
           modules.add(new OpenFileModule(reactContext));
           return modules;
       }

     //此处为必需
       @Override
       public List<Class<? extends JavaScriptModule>> createJSModules() {
           return Collections.emptyList();
       }
   }
//在mainactivity.java内注册模块(必需)
   protected List<ReactPackage> getPackages() {  
       return Arrays.<ReactPackage>asList(  
         //OpenFilePackage为上文新建的包名
               new MainReactPackage(),new OpenFilePackage());  
   } 
//js中使用
   import {NativeModules} from 'react-native';

   //注意这里的path需带文件类型后缀
   //且前面不要加‘file://’
   //直接取RNFS.ExternalDirectoryPath存储的地址
   const path = '/data/file/test.doc'
   NativeModules.OpenFileModule.show(path)

android中TextInput顶起TabBar问题

目录:android/app/src/main/AndroidManifest.xml中的<activity>标签中,添加android:windowSoftInputMode="stateAlwaysHidden|adjustPan|adjustResize"

gngcApp极光推送

苹果开发者平台:苹果开发者平台

证书配置:iOS 证书申请和使用详解

官方描述证书配置:iOS 证书设置指南

  1. 若报错:The provisioning profile specified in your build settings ("test") has an AppID of "com.baidu.test" which does not match your bundle identifier "com.apple.test"

    原因:info.plist文件中的bundle ID与创建证书时的不一致

    解决

    1. 修改info.plist文件中的bundle ID保持一致

    2. 把Build Settings中Package分栏下的Product Bundle Identifier改成新的bundle ID

App设置应用名字、图标、启动页

生成应用图标:图标工厂

只需上传一张1024*1024的应用图标,该网站会自动为你生成各种适配版本的icon,包括ios和android

ios

应用名称:Xcode内target/info/Custom iOS Target Propperties下的Bundle display name修改为应用名称

应用图标:项目目录下Images.xcassets/AppIcon内,将需要适配的图标拖进去,注意:若要上传到App Store,1024*1024的图标一定要上传

启动页关于iOS APP设置启动图片

推送通知图标:极光推送默认选取应用图标

android

应用名称:android/app/src/main/res/values/strings.xml内,修改应用名称

应用图标:android/app/src/main/res/文件夹下图标文件替换为图标工场下载下来的文件们

启动页

推送通知图标:极光推送默认选取应用图标,但在anfroid上可能行不通,android/app/src/main/res目录下说明:若没有res/drawable-xxxx/jpush_notification_icon这个资源默认使用应用图标作为通知icon,在5.0以上系统将应用图标作为默认推送图标,官网如是说。没有可以新建一个,把图标命名为相应名称。项目中res下图标用的是mipmap,不是drawable,所以新建相应路径尝试。不行的话,重启手机,此为坑。再不行,换个手机试试,可能当前手机有缓存。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 晓静是个二婚女,有一个女儿跟着前夫,前夫从来不让晓静见女儿。 现在的丈夫有个儿子,晓静改嫁到这个家庭,跟这个儿子相...
    依云70后阅读 1,560评论 12 6
  • 交通类 1.航企迎战票代公司抵抗"爬虫"抢低价票 随着机票代理手续费下调至零,不少票代动起了歪脑筋。一些公司正利用...
    古月雁小青阅读 233评论 0 0
  • 自从Captain走后根本不想回家,因为再也不会有人盼着我回去。房子只是一栋房子,并不是家,重要的是房子里住的是谁...
    经济学家杨奶奶阅读 185评论 0 1