精华内容
下载资源
问答
  • 本篇文章主要介绍了React-Native 桥接iOS原生开发详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • Ios 原生开发笔记

    千次阅读 2019-09-21 17:14:12
    本文是ios开发的学习及开发笔记 不定时更新 一个没入门的ios小白 关于window在使用singleview方式来创建项目的时候,发现 仅能在appdelegate.m中使用self.window.rootViewController是指根控制器,然后使用[self....
    本文是ios开发的学习及开发笔记 不定时更新 一个没入门的ios小白

    1. 关于window
      在使用singleview方式来创建项目的时候,发现 仅能在appdelegate.m中使用self.window.rootViewController是指根控制器,然后使用[self.window makeKeyAndVisible]; 将窗口显示出来
      关于 info.plist的 字典 Main storyboard file base name 这里当设置为空时,有时候会黑屏 即便[self.window makeKeyAndVisible]; 将指定的根控制器显示出来。
    2. 自定义启动文件
      今天看 apicloud的模块开发代码,发现他讲默认的appdelegate 进行了自定义
        #import <UIKit/UIKit.h>
    
        int main(int argc, char * argv[]) {
                @autoreleasepool {
                        return UIApplicationMain(argc, argv, nil, @"UZAppDelegate");
                }
        }

    对比 xcode 10 默认生成的main.m文件

      #import <UIKit/UIKit.h>
    #import "AppDelegate.h"
    
    int main(int argc, char * argv[]) {
        @autoreleasepool {
            return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        }
    }

    我们可以看出来 NSStringFromClass([AppDelegate class])其实就是@"AppDelegate" 也就是 指定启动文件了。

    1. 其他

    使用openwrite发布

    展开全文
  • Unity跟IOS原生开发项目融合

    万次阅读 2016-09-28 20:11:02
    需求:做一款社交类的APP,主体工程是原生开发,也就是是IOS的Xcode工程,产品经理为了丰富应用的玩法,就想往里面加上现在比较流行的AR功能,组成一款AR社交APP,我们之前见识多的都是工程是主体,然后IOS原生功能...

    更多精品文章

    Aladdin的博客

    需求:


    做一款社交类的APP,主体工程是原生开发,也就是是IOS的Xcode工程,产品经理为了丰富应用的玩法,就想往里面加上现在比较流行的AR功能,组成一款AR社交APP,我们之前见识多的都是工程是主体,然后IOS原生功能或者代码作为插件添加进Unity的Plugin里面,这样的方式参见文章(举例):Unity和Android交互让手机动起来,相关IOS方面的文章也可以参见Mono的文章。但是作为AR社交我们肯定是以IOS的Xcode功能为主体,Unity的AR功能为宿主,因为毕竟还是属于社交APP。下面就进入正题,如何将Unity的功能模块添加整合进Xcode工程里面,直接上步骤。

    介绍:Unity导出一个空的IOS项目,命名为UnityProject,原生应用命名为Native。
    [外链图片转存失败(img-wDria5OW-1564106209144)(https://img-blog.csdn.net/20160928200054444)]

    步骤:


    一、拷贝文件

    将UnityProject项目下 Classes Data Libraries MapFileParser MapFileParser.sh 等文件拷贝到Native主项根目录下
    这里写图片描述
    这里写图片描述
    这里写图片描述


    二、添加Framework

    这里写图片描述


    ###三、添加配置

    1.添加runscript

    这里写图片描述

    2.添加Search Paths

    Header Search Paths 添加
    “$(SRCROOT)/Classes”
    “$(SRCROOT)”
    $(SRCROOT)/Classes/Native
    $(SRCROOT)/Libraries/bdwgc/include
    $(SRCROOT)/Libraries/libil2cpp/include
     
    Library Search Paths 添加
    $(inherited)
    “$(SRCROOT)”
    “$(SRCROOT)/Libraries”
    

    ####3.添加预处理文件
    Classes/Prefix.pch
    这里写图片描述
    ####4.添加 -DINIT_SCRIPTING_BACKEND=1
    这里写图片描述


    ###四、修改main.m
    复制Classes/main.mm内容到main.m 修改main.m的扩展名为.mm
    删除Unity生成main.mm
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));


    ###五、修改 unityAppController

    inline UnityAppController* GetAppController()
    {
    return (UnityAppController*)[[UIApplication sharedApplication] valueForKeyPath:@"delegate.unityAppController"];
    }
    

    ###六、修改 appdelegate

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // Override point for customization after application launch.
        BOOL returnBool;
        if (_unityAppController == nil) {
             
            _unityAppController = [[UnityAppController alloc] init];
        }
        returnBool = [_unityAppController application:application didFinishLaunchingWithOptions:launchOptions];
    //    self.window = _unityAppController.window;
         
        HelloViewController *vc = [[HelloViewController alloc] init];
        self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
        self.window.rootViewController = nav;
        [self.window makeKeyAndVisible];
         
        return YES;
         
    }
     
    - (void)applicationWillResignActive:(UIApplication *)application {
        [_unityAppController applicationWillResignActive:application];
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
    }
     
    - (void)applicationDidEnterBackground:(UIApplication *)application {
        [_unityAppController applicationDidEnterBackground:application];
     
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }
     
    - (void)applicationWillEnterForeground:(UIApplication *)application {
        [_unityAppController applicationWillEnterForeground:application];
     
        // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
    }
     
    - (void)applicationDidBecomeActive:(UIApplication *)application {
        [_unityAppController applicationDidBecomeActive:application];
     
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }
     
    - (void)applicationWillTerminate:(UIApplication *)application {
        [_unityAppController applicationWillTerminate:application];
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }
    

    ###七、Error

    ####1、Expected identifier or ‘(‘
    修改UnityViewControllerBaseiOS.h
    这里写图片描述

    #ifdef __cplusplus
    extern "C" {
    #endif
        void AddViewControllerRotationHandling(Class class_, IMP willRotateToInterfaceOrientation, IMP didRotateFromInterfaceOrientation, IMP viewWillTransitionToSize);
    #ifdef __cplusplus
    }
    #endif
     
    #ifdef __cplusplus
    extern "C" {
    #endif
        void AddViewControllerDefaultRotationHandling(Class class_);
    #ifdef __cplusplus
    }
    #endif
    

    ####2、如果存在多个pch配置文件,需要整合为一个
    ####3、Unity和Xcode版本会存在兼容问题,最好都升级到最新,否则会碰到莫名其妙的报错

    ###八、关于EasyAR的提示
    如果使用EasyAR的话,会出现融合后黑屏的问题,解决如下
    这里写图片描述


    欢迎关注我的围脖
    ==================== 迂者 丁小未 CSDN博客专栏=================

    MyBlog:http://blog.csdn.net/dingxiaowei2013 MyQQ:1213250243

    Unity QQ群:375151422 cocos2dx QQ群:280818155

    ====================== 相互学习,共同进步 ===================

    unity交流群

    QQ群
    unity3d unity 游戏开发

    展开全文
  • 想要给项目添加开屏广告,但是没有广点通的相关插件,所以只能从原生那里入手。 想法是在进入flutter界面前,添加一个开屏,开屏结束后进入flutter 根据 https://github.com/gdtmobsdk/GDTMobSDK 配置好sdk后 ...
  • //获取当前时间  NSDate * timeDate=[NSDate date];  NSDateFormatter *dateformatter=[[NSDateFormatter alloc] init];  [dateformatter setDateFormat:@"HH:mm:ss"]; ... NSString * locationString=[da
    //获取当前时间
        NSDate *  timeDate=[NSDate date];
        NSDateFormatter  *dateformatter=[[NSDateFormatter alloc] init];
        [dateformatter setDateFormat:@"HH:mm:ss"];
        NSString *  locationString=[dateformatter stringFromDate:timeDate];
        NSLog(@"locationString is %@",locationString);
        
    //    获取当前日期
        NSCalendar* cal = [NSCalendar currentCalendar];
        NSUInteger unitFlags = NSDayCalendarUnit|NSMonthCalendarUnit | NSYearCalendarUnit;
        NSDateComponents* conponent = [cal components:unitFlags fromDate:timeDate];
        NSInteger year = [conponent year];
        NSInteger month = [conponent month];
        NSInteger day = [conponent day];
        NSString* nsDateString = [NSString stringWithFormat:@"%4ld年%2ld月%2ld日",year,month,day];
        NSLog(@"nsDateString is %@",nsDateString);

    展开全文
  • 我平时在用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
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    展开全文
  • iOS原生地图开发指南2

    2016-01-08 18:01:32
    iOS原生地图开发指南续——大头针与自定义标注 在上一篇博客中http://my.oschina.net/u/2340880/blog/415360系统总结了iOS原生地图框架MapKit中主体地图的设置与应用。这篇是上一篇的一个后续,总结了系统的...
  • Flutter插件开发iOS原生模块开发

    千次阅读 2019-05-26 16:20:37
    上一篇简单的整理了一下Podspec语法整理,主要是为了这一篇Flutter中iOS原生模块开发。 简介 在开发Flutte中我们难免会遇到原生组件、插件或者与原生模块通信,比如地图、引入第三方sdk如微信、支付宝等SDK,还有...
  • iOS原生与H5交互开发

    千次阅读 2017-04-20 10:51:45
    HTML5与Native的混合开发iOS 开发之 原生+html5混合开发 [[ 方法互调 ]]iOS与HTML5交互方法总结基于HTML5之APP页面间的传值的几种方式iOS原生APP与H5+JS交互
  • iOS原生混合RN开发详解 做过原生iOS开发或者Android开发的同学们肯定也都了解Hybrid,有一些Hybrid的开发经验,目前我们企业开发中运用最广泛的Hybrid App技术就是原生与H5 hybrid,在早期的时候,可能部分同学也...
  • iOS 原生与 JS 交互 iOS与JS交互的方法 iOS与JS交互的方法: 1、拦截url(适用于UIWebView和WKWebView) 2、JavaScriptCore(只适用于UIWebView,iOS7+) 3、WKScriptMessageHandler(只适用于WKWebView,iOS8+) 4...
  • iOS原生H5交互开发

    2016-03-05 19:33:08
    此文件是一个 OC工程文件, 主要演示OC和H5 交互开发。 注:此文件为网上的资源,为了防止以后丢失找不到上传到CSDN备份。在此感谢次文件原作者。
  • ios原生地图开发

    千次阅读 2015-08-21 12:33:56
    开发环境:Xcode6.4 模拟器 : IOS8.4 OS X : 10.0.4 小编博客链接: http://www.goofyy.com 首先例子是小编写的一个定位获取经纬度,然后在地图上面显示,并自定义大头针的一个程序。先上图 首先说一下定位,在 ...
  • iOS混合开发1.前言2.项目背景3.项目框架4.从入坑到踩坑5.从踩坑到挖坑 1.前言     前端统一开发越来越多,公司为了大一统前端的所有页面显示问题,同时为节约人力资源成本,决定做前端统一开发的预研以及选型。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,530
精华内容 2,212
关键字:

ios原生开发