精华内容
下载资源
问答
  • 我平时在用React Native开发App时会用到一些原生模块,比如:在做社会化分享、第三方登录、扫描、通信录,日历等等,想必大家也是一样。 关于在React Native中使用原生模块,在这里引用React Nati

    前言

    一直想写一下我在React Native原生模块封装方面的一些经验和心得,来分享给大家,但实在抽不开身,今天看了一下日历发现马上就春节了,所以就赶在春节之前将这篇博文写好并发布(其实是两篇:要看Android篇的点这里《React Native Android原生模块开发》)。

    我平时在用React Native开发App时会用到一些原生模块,比如:在做社会化分享、第三方登录、扫描、通信录,日历等等,想必大家也是一样。

    关于在React Native中使用原生模块,在这里引用React Native官方文档的一段话:

    有时候App需要访问平台API,但在React Native可能还没有相应的模块。或者你需要复用一些Java代码,而不想用JavaScript再重新实现一遍;又或者你需要实现某些高性能的、多线程的代码,譬如图片处理、数据库、或者一些高级扩展等等。
    我们把React Native设计为可以在其基础上编写真正的原生代码,并且可以访问平台所有的能力。这是一个相对高级的特性,我们并不期望它应当在日常开发的过程中经常出现,但它确实必不可少,而且是存在的。如果React Native还不支持某个你需要的原生特性,你应当可以自己实现对该特性的封装。

    上面是我翻译React Native官方文档上的一段话,大家如果想看英文版可以点这里:Native Modules
    在这篇文章中呢,我会带着大家来开发一个从相册获取照片并裁切照片的项目,并结合这个项目来具体讲解一下如何一步步开发React Native iOS原生模块的。

    React Native iOS原生模块开发实战-教程-心得-如何创建一个React Native iOS原生模块

    提示:告诉大家一个好消息,React Native视频教程发布了,大家现可以看视频学React Native了。

    首先,让我们先看一下,开发iOS原生模块的主要流程。

    开发iOS原生模块的主要流程

    在这里我把构建React Native iOS原生模块的流程概括为以下三大步:

    1. 编写原生模块的相关iOS代码;
    2. 暴露接口与数据交互;
    3. 导出React Native原生模块;

    接下来让我们一起来看一下每一步所需要做的一些事情。

    原生模块开发实战

    在这里我们就以开发一个从相册获取照片并裁切照片的实战项目,来具体讲解一下如何开发React Native iOS原生模块的。

    编写原生模块的相关iOS代码

    这一步我们需要用到XCode。
    首先我们用XCode打开React Native项目根目录下的iOS项目,如图:

    open-react-native-iOS-native-project

    接下来呢,我们就可以编写iOS代码了。

    首先呢,我们先来实现一个Crop接口:

     

    @interface Crop:NSObject<UIImagePickerControllerDelegate,UINavigationControllerDelegate>
    -(instancetype)initWithViewController:(UIViewController *)vc;
    typedef void(^PickSuccess)(NSDictionary *resultDic);
    typedef void(^PickFailure)(NSString* message);
    @property (nonatomic, retain) NSMutableDictionary *response;
    @property (nonatomic,copy)PickSuccess pickSuccess;
    @property (nonatomic,copy)PickFailure pickFailure;
    @property(nonatomic,strong)UIViewController *viewController;
    
    -(void)selectImage:(NSDictionary*)option successs:(PickSuccess)success failure:(PickFailure)failure;
    @end
    

    查看视频教程

    我们创建一个Crop.m,在这个类中呢,我们实现了从相册选择照片以及裁切照片的功能:

     

    /**
     * React Native iOS原生模块开发
     * Author: CrazyCodeBoy
     * 技术博文:http://www.devio.org
     * GitHub:https://github.com/crazycodeboy
     * Email:crazycodeboy@gmail.com
     */
    
    #import "Crop.h"
    #import <AssetsLibrary/AssetsLibrary.h>
    @interface Crop ()
    @property(strong,nonatomic)NSDictionary*option;
    @end
    
    @implementation Crop
    -(instancetype)initWithViewController:(UIViewController *)vc{
      self=[super init];
      self.viewController=vc;
      return self;
    }
    
    -(void)selectImage:(NSDictionary*)option successs:(PickSuccess)success failure:(PickFailure)failure{
      self.pickSuccess=success;
      self.pickFailure=failure;
      self.option=option;
      UIImagePickerController *pickerController = [[UIImagePickerController alloc] init];
      pickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
      pickerController.delegate = self;
      pickerController.allowsEditing = YES;
      [self.viewController presentViewController:pickerController animated:YES completion:nil];
    }
    
    //省略部分代码...
    
    #pragma mark 获取临时文件路径
    -(NSString*)getTempFile:(NSString*)fileName{
      NSString *imageContent=[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingString:@"/temp"];
      NSFileManager * fileManager = [NSFileManager defaultManager];
      if (![fileManager fileExistsAtPath:imageContent]) {
        [fileManager createDirectoryAtPath:imageContent withIntermediateDirectories:YES attributes:nil error:nil];
      }
      return [imageContent stringByAppendingPathComponent:fileName];
    }
    -(NSString*)getFileName:(NSDictionary*)info{
      NSString *fileName;
      NSString *tempFileName = [[NSUUID UUID] UUIDString];
      fileName = [tempFileName stringByAppendingString:@".jpg"];
      return fileName;
    }
    @end
    

    查看视频教程

    实现了从相册选择照片以及裁切照片的功能之后呢,接下来我们需要将iOS原生模块暴露给React Native,以供js调用。

    暴露接口与数据交互

    接下了我们就向React Native暴露接口以及做一些数据交互部分的操作。为了暴露接口以及进行数据交互我们需要借助React Native的React/RCTBridgeModule.h,在这里我们创建一个ImageCrop类让它实现RCTBridgeModule协议。

    创建一个ImageCrop

    ImageCrop.h

     

    /**
     * React Native iOS原生模块开发
     * Author: CrazyCodeBoy
     * 技术博文:http://www.devio.org
     * GitHub:https://github.com/crazycodeboy
     * Email:crazycodeboy@gmail.com
     */
    
    
    #import <Foundation/Foundation.h>
    #import <React/RCTBridgeModule.h>
    @interface  ImageCrop: NSObject <RCTBridgeModule>
    
    @end
    

    查看视频教程

    ImageCrop.m

     

    /**
     * React Native iOS原生模块开发
     * Author: CrazyCodeBoy
     * 技术博文:http://www.devio.org
     * GitHub:https://github.com/crazycodeboy
     * Email:crazycodeboy@gmail.com
     */
    
    
    #import "ImageCrop.h"
    #import "Crop.h"
    
    @interface ImageCrop ()
    @property(strong,nonatomic)Crop *crop;
    @end
    
    @implementation ImageCrop
    
    
    RCT_EXPORT_MODULE();
    
    - (dispatch_queue_t)methodQueue 
    {
      return dispatch_get_main_queue();
    }
    RCT_EXPORT_METHOD(selectWithCrop:(NSInteger)aspectX aspectY:(NSInteger)aspectY resolver:(RCTPromiseResolveBlock)resolve
                      rejecter:(RCTPromiseRejectBlock)reject)
    {
        UIViewController *root = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
        while (root.presentedViewController != nil) {
          root = root.presentedViewController;
        }
      NSString*aspectXStr=[NSString stringWithFormat: @"%ld",aspectX];
      NSString*aspectYStr=[NSString stringWithFormat: @"%ld",aspectY];
      [[self _crop:root] selectImage:@{@"aspectX":aspectXStr,@"aspectY":aspectYStr} successs:^(NSDictionary *resultDic) {
        resolve(resultDic);
      } failure:^(NSString *message) {
        reject(@"fail",message,nil);
      }];
    }
    
    //省略部分代码...
    
    @end
    

    查看视频教程

    ImageCrop类中,我们调用了Crop类来实现从iOS相册中获取图片并裁切图片的功能,在调用Crop的时候我们用的是懒加载的方式。为什么要用懒加载呢?这是为了避免当我们多次调用原生模块从相册选择照片的时候创建多个Crop实例情况的发生。

    另外,需要特别提到的是,我们对Crop实例设置了强引用,这是为了防止在我们调用相册的时候Crop被回收,如果Crop被回收我们就无法收到选择照片之后的回调了,也就无法获取到照片。

    暴露接口

    在上述代码中我们通过RCT_EXPORT_METHOD宏来声明向React Native暴露的接口,这样以来我们就可以在js文件中通过ImageCrop.selectWithCrop来调用我们所暴露给React Native的接口了。

    接下来呢,我们来看一下原生模块和JS模块是如何进行数据交互的?

    原生模块和JS进行数据交互

    在我们要实现的从相册选择照片并裁切的项目中,JS模块需要告诉原生模块照片裁切的比例,等照片裁切完成后,原生模块需要对JS模块进行回调来告诉JS模块照片裁切的结果,在这里我们需要将照片裁切后生成的图片的路径告诉JS模块。

    提示:在所有的情况下js和原生模块之前进行通信都是在异步的情况下进行的。

    接下来我们就来看下一JS是如何向原生模块传递数据的?

    JS向原生模块传递数据:

    为了实现JS向原生模块进行传递数据,我们可以直接通过调用原生模块所暴露出来的接口,来为接口方法设置参数。这样以来我们就可以将数据通过接口参数传递到原生模块中,如:

     

    RCT_EXPORT_METHOD(selectWithCrop:(NSInteger)aspectX aspectY:(NSInteger)aspectY resolver:(RCTPromiseResolveBlock)resolve
                      rejecter:(RCTPromiseRejectBlock)reject)
    

    通过上述代码我们可以看出,JS模块可以通过selectWithCrop方法来告诉原生模块要裁切照片的宽高比,最后两个参数是一个Promise,照片裁剪完成之后呢,原生模块可以通过Promise来对JS模块进行回调,来告诉裁切结果。

    既然是js和Object-c进行数据传递,那么他们两者之间是如何进行类型转换的呢:
    在上述例子中我们通过RCT_EXPORT_METHOD宏来声明需要暴露的接口,被 RCT_EXPORT_METHOD标注的方法支持如下几种数据类型。

    RCT_EXPORT_METHOD标注的方法支持如下几种数据类型的参数:

     

    string (NSString)
    number (NSInteger, float, double, CGFloat, NSNumber)
    boolean (BOOL, NSNumber)
    array (NSArray) 包含本列表中任意类型
    object (NSDictionary) 包含string类型的键和本列表中任意类型的值
    function (RCTResponseSenderBlock)
    

    原生模块向JS传递数据:

    原生模块向JS传递数据我们可以借助Callbacks与Promises,接下来就讲一下如何通过他们两个进行数据传递的。

    Callbacks

    原生模块支持一个特殊类型的参数-Callbacks,我们可以通过它来对js进行回调,以告诉js调用原生模块方法的结果。
    将我们selectWithCrop的参数改为Callbacks之后:

     

    RCT_EXPORT_METHOD(selectWithCrop:(NSInteger)aspectX aspectY:(NSInteger)aspectY success:(RCTResponseSenderBlock)success failure:(RCTResponseErrorBlock)failure)
    {
        UIViewController *root = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
        while (root.presentedViewController != nil) {
          root = root.presentedViewController;
        }
      NSString*aspectXStr=[NSString stringWithFormat: @"%ld",aspectX];
      NSString*aspectYStr=[NSString stringWithFormat: @"%ld",aspectY];
      [[self _crop:root] selectImage:@{@"aspectX":aspectXStr,@"aspectY":aspectYStr} successs:^(NSDictionary *resultDic) {
        success(@[[NSNull null],@[@"imageUrl",[resultDic objectForKey:@"imageUrl"]]]);
      } failure:^(NSString *message) {
        failure(nil);
      }];
    }
    
    

    查看视频教程

    在上述代码中我们实现了通过Callback来对js进行回调。

    接下来呢,我们在js中就可以这样来调用我们所暴露的接口:

     

    ImageCrop.selectWithCrop(parseInt(x),parseInt(y),(error, result)=>{
     if (error) {
        console.error(error);
      } else {
        console.log(result);
      }
    })
    

    提示:另外要告诉大家的是,无论是Callback还是我接下来要讲的Promise,我们只能调用一次,也就是"you call me once,I can only call you once"。

    Promises

    除了上文所讲的Callback之外React Native还为了我们提供了另外一种回调js的方式叫-Promise。如果我们暴露的接口方法的最后一个参数是Promise时,如:

     

    RCT_EXPORT_METHOD(selectWithCrop:(NSInteger)aspectX aspectY:(NSInteger)aspectY resolver:(RCTPromiseResolveBlock)resolve
                      rejecter:(RCTPromiseRejectBlock)reject)
    

    那么当js调用它的时候将会返回一个Promsie:

     

    ImageCrop.selectWithCrop(parseInt(x),parseInt(y)).then(result=> {
        this.setState({
            result: result
        })
    }).catch(e=> {
        this.setState({
            result: e
        })
    });
    

    另外,我们也可以使用ES2016的 async/await语法,来简化我们的代码:

     

    async onSelectCrop() {
        var result=await ImageCrop.selectWithCrop(parseInt(x),parseInt(y));
    }
    

    这样以来代码就简化了很多。

    因为,基于回调的数据传递无论是Callback还是Promise,都只能调用一次。但,在实际项目开发中我们有时会向js多次传递数据,比如二维码扫描原生模块,针对这种多次数据传递的情况我们该怎么实现呢?

    接下来我就为大家介绍一种原生模块可以向js多次传递数据的方式:

    向js发送事件

    在原生模块中我们可以向js发送多次事件,即使原生模块没有被直接的调用。为了向js传递事件我们需要用到RCTEventDispatcher,它是原生模块和js之间的一个事件调度管理器。

     

    #import "RCTBridge.h"
    #import "RCTEventDispatcher.h"
    
    @implementation CalendarManager
    
    @synthesize bridge = _bridge;
    
    - (void)calendarEventReminderReceived:(NSNotification *)notification
    {
      NSString *eventName = notification.userInfo[@"name"];
      [self.bridge.eventDispatcher sendAppEventWithName:@"EventReminder"
                                                   body:@{@"name": eventName}];
    }
    

    在上述方法中我们可以向JS模块发送任意次数的事件,其中eventName是我们要发送事件的事件名,params是此次事件所携带的数据,接下来呢我们就可以在JS模块中监听这个事件了:

     

    import { NativeAppEventEmitter } from 'react-native';
    
    var subscription = NativeAppEventEmitter.addListener(
      'EventReminder',
      (reminder) => console.log(reminder.name)
    );
    ...
    

    另外,不要忘记在组件被卸载的时候移除监听:

     

    componentWillUnmount(){
        subscription.remove();
    }
    

    到现在呢,暴露接口以及数据传递已经进行完了,接下来呢,我们就需要导出React Native原生模块了。

    导出React Native原生模块

    为了方面我们使用刚才创建的原生模块,我们需要为它导出一个相应的JS模块。

    我们创建一个ImageCrop.js文件,然后添加如下代码:

     

    import { NativeModules } from 'react-native';
    export default NativeModules.ImageCrop;
    

    这样以来呢,我们就可以在其他地方通过下面方式来使用我们所导出的这个模块了:

     

    import ImageCrop from './ImageCrop' //导入ImageCrop.js
    //...省略部分代码
    
        onSelectCrop() {
            let x=this.aspectX?this.aspectX:ASPECT_X;
            let y=this.aspectY?this.aspectY:ASPECT_Y;
            ImageCrop.selectWithCrop(parseInt(x),parseInt(y)).then(result=> {
                this.setState({
                    result: result
                })
            }).catch(e=> {
                this.setState({
                    result: e
                })
            });
        }
    //...省略部分代码
    }
    

    查看视频教程

    现在呢,我们这个原生模块就开发好了,而且我们也使用了我们的这个原生模块。

    关于线程

    React Native在一个独立的串行GCD队列中调用原生模块的方法。在我们为React Native开发原生模块的时候,如果有耗时的操作比如:文件读写、网络操作等,我们需要新开辟一个线程,不然的话,这些耗时的操作会阻塞JS线程。通过实现方法- (dispatch_queue_t)methodQueue,原生模块可以指定自己想在哪个队列中被执行。
    具体来说,如果模块需要调用一些必须在主线程才能使用的API,那应当这样指定:

     

    - (dispatch_queue_t)methodQueue
    {
      return dispatch_get_main_queue();
    }
    

    类似的,如果一个操作需要花费很长时间,原生模块不应该阻塞住,而是应当声明一个用于执行操作的独立队列。举个例子,RCTAsyncLocalStorage模块创建了自己的一个queue,这样它在做一些较慢的磁盘操作的时候就不会阻塞住React本身的消息队列:

     

    - (dispatch_queue_t)methodQueue
    {
      return dispatch_queue_create("com.facebook.React.AsyncLocalStorageQueue", DISPATCH_QUEUE_SERIAL);
    }
    

    指定的methodQueue会被模块里的所有方法共享。如果你的方法中“只有一个”是耗时较长的(或者是由于某种原因必须在不同的队列中运行的),你可以在函数体内用dispatch_async方法来在另一个队列执行,而不影响其他方法:

     

     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        if (url) {
          [assetLibrary assetForURL:url resultBlock:^(ALAsset *asset) {
            ALAssetRepresentation *rep = [asset defaultRepresentation];
            Byte *buffer = (Byte*)malloc((unsigned long)rep.size);
            NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:((unsigned long)rep.size) error:nil];
            NSData *data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
            NSString * imagePath = [imageContent stringByAppendingPathComponent:fileName];
            [data writeToFile:imagePath atomically:YES];
            handler(imagePath);
          } failureBlock:^(NSError *error) {
            handler(@"获取图片失败");
          }];
        }
      });
    

    查看视频教程

    在上述代码中我们将文件写入操作放到了一个独立的线程队列中,这样以来即使文件写入的时间再长也不会阻塞其他线程。

    还有一个需要告诉大家的是,如果原生模块中需要更新UI,我们需要获取主线程,然后在主线程中更新UI,如:

     

        dispatch_async(dispatch_get_main_queue(), ^{
            [picker dismissViewControllerAnimated:YES completion:dismissCompletionBlock];
        });
    

    关于React Native iOS原生模块的多线程无外乎这些东西。

    告诉大家一个好消息,为大家精心准备的React Native视频教程发布了,大家现可以看视频学React Native了。

    如果,大家在开发原生模块中遇到问题可以在本文的下方进行留言,我看到了后会及时回复的哦。
    另外也可以关注我的新浪微博,或者关注我的Github来获取更多有关React Native开发的技术干货

    推荐学习:视频教程《最新版React Native+Redux打造高质量上线App》



    作者:CrazyCodeBoy
    链接:https://www.jianshu.com/p/24a86ab76ac6
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    展开全文
  • React Native开发原生Android,IOS教程
    展开全文
  • 自Egret Native1.0系列稳定版发布后,我们基于项目开发实战,从开发者反馈的各种问题入手,针对音频系统、网络系统、输入法、文字渲染、原生渲染在内的多个模块进行渐进式重构,为开发者带来了更稳定和性能更好的...

    自Egret Native1.0系列稳定版发布后,我们基于项目开发实战,从开发者反馈的各种问题入手,针对音频系统、网络系统、输入法、文字渲染、原生渲染在内的多个模块进行渐进式重构,为开发者带来了更稳定和性能更好的Egret Native新版本。

    现在,使用Egret 打包Android / iOS 原生游戏的开发者越来越多,打包过程中也会遇到各种小问题,为了帮助更多的开发者掌握原生游戏打包技巧,我们准备了今天的视频内容:

    Egret 打包Android/iOS原生游戏

    项目打包过程中,若您还有不明白的地方可以跟我们官方技术客服:egretengin(微信号)联系,我们竭诚为您答疑解惑!

    展开全文
  •  按照教程我们初始化了helloworld项目 如下 路径为/usr/local/Cellar/nvm/0.29.0/HelloWorld 但是大家会发现使用react-native init AwesomeProject创建 react native很慢 这个解决方式如下:编

    1.环境搭建。参考教程:http://www.tuicool.com/articles/V3U3UbU   常见的环境问题可以参考此网站http://www.jianshu.com/p/fa0c19a31656


          按照教程我们初始化了helloworld项目。  路径为/usr/local/Cellar/nvm/0.29.0/HelloWorld 但是大家会发现使用react-native init AwesomeProject创建 react native很慢 这个解决方式如下:编辑 ~/.npmrc 加入下面内容registry =https://registry.npm.taobao.org 重启下命令行.

    可以直接用-更改镜像文件。

    npm config set registry https://registry.npm.taobao.org

    npm config set disturl https://npm.taobao.org/dist

    步骤如下:

    1.sudo npm install -g react-tools 安装react-tools

    2.sudo npm install -g react-native-cli

    3.react-native init HelloWorld



    这样就在这个目录下创建了helloWorld的项目了。(我的路径为:/usr/local/Cellar/nvm/)可以就在此目录下面开发。也可集成原生项目!将此目录的node_modules的文件夹拷贝到自己的原生项目下面。如下

    2.可以看到这个目录:

    这个node_modules目录 将其拷贝到自己项目的根目录。


    3.打开Podfile 文件 输入

    #react native
    pod 'React', :path => './node_modules/react-native', :subspecs => [
    'Core',
    'RCTImage',
    'RCTNetwork',
    'RCTText',
    'RCTWebSocket',
    # 添加其他你想在工程中使用的依赖。
    ]

    4 pod install 安装


    5.按照如图所示的建代码,



    会一点iOS开发的人应该看的懂 就不细说怎么创建了。


    js的代码如下

    /**
     * Sample React Native App
     * https://github.com/facebook/react-native
     * @flow
     */
    
    import React, { Component } from 'react';
    import {
      AppRegistry,
      StyleSheet,
      Text,
      View
    } from 'react-native';
    
    class HelloWorld extends Component {
      render() {
        return (
          <View style={styles.container}>
            <Text style={styles.welcome}>
              Welcome to React Native!
            </Text>
            <Text style={styles.instructions}>
              To get started, edit index.ios.js
            </Text>
            <Text style={styles.instructions}>
              Press Cmd+R to reload,{'\n'}
              Cmd+D or shake for dev menu
            </Text>
          </View>
        );
      }
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
      },
      welcome: {
        fontSize: 20,
        textAlign: 'center',
        margin: 10,
      },
      instructions: {
        textAlign: 'center',
        color: '#333333',
        marginBottom: 5,
      },
    });
    
    AppRegistry.registerComponent('HelloWorld', () => HelloWorld);
    
    


    在ReactNative1VC里面添加代码

    #import "ReactNative1VC.h"
    #import "RCTRootView.h"
    
    
    @interface ReactNative1VC ()
    @end
    
    @implementation ReactNative1VC
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        NSURL *jsCodeLocation;
        
        [[RCTBundleURLProvider sharedSettings] setDefaults];
        jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
        
        RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                            moduleName:@"HelloWorld"
                                                     initialProperties:nil
                                                         launchOptions:nil];
        
        rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
        rootView.frame=[UIScreen mainScreen].bounds;
        [self.view addSubview:rootView];
        
    }
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    

    运行之后出现如下图:


    因为是热更新,所以代码在服务器上面。现在我们拿本地来作为服务器:

    进入目录cd Pods/React; npm run start 开启node.js服务器

    如果报如下错误:


    表示路径有问题。


    最后我们可以看到如图

       OK 一切大功告成了。新的旅程即将开始哦!!!


    如果我已经存在了iOS的原生应用,只是部分需要react native的开发工作,那么先用上述方法创建hello 项目,再把原生的直接add 进去然后改一下相关setting项这样比在原生项目里面是比较合理的做法。不要用pod 引入第三方react native。这样会有莫名其妙的问题。

    好如下:报的错误百度都是可以搜到的

     






    展开全文
  • iOS_Cordova开发教程

    2017-11-06 16:57:31
    公司准备开发一套APP,嗯,一个系列的APP,除了一个页面跟业务相关的不同,其他界面基本一致,因此,产品萌生一个想法,关于webAPP的想法。对,苦逼的程序员负责调研可行性以及整体的方案流程。目的为了达到除了业务...
  • 2020新款开发萌萌直播社交视频社区精品移动双端原生开发源码直播APP系统源码带代理版 该商品为原生系统源码(包含后端源码,Android源码,IOS源码) 全源码2020新款开发萌萌直播社交视频社区精品移动双端原生开发...
  • 即时聊天通讯软件安卓+ios双端原生源码 包括安卓源码,ios源码,后端为php开发 不带搭建教程,下载的会员请自行研究!...
  • 下面有个Demo介绍原生iOS项目是如何与React Native集成的。先贴下React Native中文网是官方教程:[React Native嵌入到现有原生应用](https://reactnative.cn/docs/0.43/integration-with-existing-apps/) ...
  • 原生OC开发IOS Unity开发IOS 重要步骤 网上关于这类教程的文档也比较多,当然并不一定你照着做就能一帆风顺的能够实现,或许是因为一些软件是老版本,又或者是其他细节性的没注意到,我也是照着做然后...

空空如也

空空如也

1 2 3 4 5 ... 13
收藏数 248
精华内容 99
热门标签
关键字:

ios原生开发教程