美文网首页
RN开发填坑之旅

RN开发填坑之旅

作者: 娘娘羌 | 来源:发表于2019-02-21 16:25 被阅读0次

    大概是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,所以新建相应路径尝试。不行的话,重启手机,此为坑。再不行,换个手机试试,可能当前手机有缓存。

    相关文章

      网友评论

          本文标题:RN开发填坑之旅

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