아직 구글에 제대로된 메뉴얼이나 없어서
실제 기능까지 확인후 작성한 메뉴얼입니다.
스펙 사양 :
react-native: 0.64.1
node : 15.14.0
안드로이드 10과 충돌을 예방을 위하여 node 12를 추천함
android:
buildToolsVersion = "29.0.3"
minSdkVersion = 21
compileSdkVersion = 29
targetSdkVersion = 29
ndkVersion = "20.1.5948944"
Xcode: 12
설치 :
1. react-native-channel-plugin 플러그인 라이브러리 설치
react-native install react-native-channel-plugin
만약 수동으로 설치를 원한다면, 아래 2가지 명령을 실행하면 된다.
npm install react-native-channel-plugin
react-native link react-native-channel-plugin
2. IOS
ios 는 Cocoapods와 Carthage 2가지 설치방법이 있는데
나는 Cocoapods를 사용했다.
혹시나 Carthage 설치가 필요하다면 링크를 걸어놓으니 개인적으로 확인하길 바란다.
https://developers.channel.io/docs/react-native-installation
공식 문서에서 요구하는 사양은
Xcode 12, CocoaPods >= 1.10.0.rc.1 이다.
특히 CocoaPods는 버전을 꼭 확인해서 해당버전 이상을 사용하라고 한다.
앞에서 react-native install 명령을 사용해 설치하면 자동 설정되어
pod 파일을 설정 할필요가 없지만,
만약 수동 설치를 해다면 아래 와 같이 pod 파일을 변경해준다.
// 0.63버전 이상
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
platform :ios, '10.0'
target 'TestChannel' do
config = use_native_modules!
use_react_native!(
:path => config[:reactNativePath],
# to enable hermes on iOS, change `false` to `true` and then install pods
:hermes_enabled => false
)
pod 'ChannelIOSDK', podspec: 'https://mobile-static.channel.io/ios/latest/framework.podspec' // 여기 추가
pod 'RNChannelIO', :path => '../node_modules/react-native-channel-plugin' // 여기 추가
target 'TestChannelTests' do
inherit! :complete
# Pods for testing
end
# Enables Flipper.
#
# Note that if you have use_frameworks! enabled, Flipper will not work and
# you should disable the next line.
# use_flipper!()
# post_install do |installer|
# react_native_post_install(installer)
# end
end
// 0.62 이하 버전
platform :ios, '10.0'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
use_modular_headers!
target 'YourApplicationName' do
# Pods for examples
pod 'React', :path => '../node_modules/react-native/', :modular_headers => false
pod 'React-Core', :path => '../node_modules/react-native/React', :modular_headers => false
pod 'React-DevSupport', :path => '../node_modules/react-native/React', :modular_headers => false
pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS', :modular_headers => false
pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation', :modular_headers => false
pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob', :modular_headers => false
pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image', :modular_headers => false
pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS', :modular_headers => false
pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network', :modular_headers => false
pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings', :modular_headers => false
pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text', :modular_headers => false
pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration', :modular_headers => false
pod 'React-RCTWebSocket', :path => '../node_modules/react-native/Libraries/WebSocket', :modular_headers => false
pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact', :modular_headers => false
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi', :modular_headers => false, :modular_headers => false
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor', :modular_headers => false
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector', :modular_headers => false
pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga', :modular_headers => false
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec', :modular_headers => false
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec', :modular_headers => false
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec', :modular_headers => false
pod 'RNChannelIO', :path => '../node_modules/react-native-channel-plugin', :modular_headers => true
pod 'RNCPushNotificationIOS', :path => '../node_modules/@react-native-community/push-notification-ios', :modular_headers => false
target 'YourApplicationNameTests' do
inherit! :search_paths
# Pods for testing
end
use_native_modules!
end
자 이제 npx pod-install 명령으로 라이브러리를 다운받아 적용해보자
공식문서에 말하기를 React-Native ios프로젝트는 순수 Object-c라
몇가지 build settings 수정이 필요하다고 한다.
User-Defined Setting 란에 가서 (없으면 추가)
SWIFT_VERSION키에 값은 5.0를 변경
React-Native 0.63 or higher : channelIO 사용에 대한 swift5 의존성 준비가 아직 안되어서
빈 .swift 파일 과 bridge header 파일 생성 (나는 안해도 이상이 없었다.)
info.plist파일에 권한을 추가한다.
Privacy - Camera Usage Description | Accessing to camera in order to provide better user experience |
Privacy - Photo Library Usage Description | Accessing to photo library in order to provide better user experience |
Privacy - Photo Library Additions Usage Description | Accessing to photo library in order to save photos |
Privacy - Microphone Usage Description | Accessing to microphone to record voice for video |
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
// #ifdef FB_SONARKIT_ENABLED
// #import <FlipperKit/FlipperClient.h>
// #import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
// #import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
// #import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
// #import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
// #import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
// static void InitializeFlipper(UIApplication *application) {
// FlipperClient *client = [FlipperClient sharedClient];
// SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
// [client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
// [client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
// [client addPlugin:[FlipperKitReactPlugin new]];
// [client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
// [client start];
// }
// #endif
@import ChannelIO; // 여기 추가
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// #ifdef FB_SONARKIT_ENABLED
// InitializeFlipper(application);
// #endif
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@"TestChannel"
initialProperties:nil];
if (@available(iOS 13.0, *)) {
rootView.backgroundColor = [UIColor systemBackgroundColor];
} else {
rootView.backgroundColor = [UIColor whiteColor];
}
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
[ChannelIO initialize:application]; // 여기 추가
return YES;
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
@end
AppDelegate.m 파일을 수정한다.
만약 SceneDelegate.m 파일을 사용한다면 아래와 같이 수정해준다.
// SceneDelegate.m
@interface SceneDelegate ()
@property (strong, nonatomic) UIWindow * channelWindow;
@end
@implementation SceneDelegate
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
_channelWindow = [ChannelIO initializeWindowWith:(UIWindowScene *)scene];
}
@end
Flipper은 ChannelIO와 충돌이 일어나니 전부 주석 처리 해주면 된다.
# use_flipper!
# post_install do |installer|
# flipper_post_install(installer)
# end
// AppDelegate.m
// Comment out Flipper.
...
//#import <FlipperKit/FlipperClient.h>
//#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
//#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
//#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
//#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
//#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
...
//static void InitializeFlipper(UIApplication *application) {
// FlipperClient *client = [FlipperClient sharedClient];
// SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
// [client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
// [client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
// [client addPlugin:[FlipperKitReactPlugin new]];
// [client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
// [client start];
//}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
//#ifdef FB_SONARKIT_ENABLED
// InitializeFlipper(application);
//#endif
...
}
그리고 마지막으로 Build Settings 에 Library Search Paths 를 찾아
더블클릭 후에 '$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)' 삭제 한다.
3. Android
ChannelIO는 multidex 설정이 필요한데, 안드로이드 21 이상에서는 기본 사용설정이 되므로
설정이 필요 하지 않지만 그이하 버전은 설정이 필요하다.
아래 랭크를 참고해서 설정해주면 된다.
https://developer.android.com/studio/build/multidex?hl=ko
// android/app/build.gradle
android {
...
defaultConfig {
multiDexEnabled true // 여기 추가
}
...
}
// MainApplication.java
package com.testchannel;
import android.app.Application;
import android.content.Context;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.zoyi.channel.plugin.android.ChannelIO; // 여기 추가
import com.zoyi.channel.rn.RNChannelIOPackage; // 여기 추가
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
ChannelIO.initialize(this); // 여기 추가
}
/**
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
*
* @param context
* @param reactInstanceManager
*/
private static void initializeFlipper(
Context context, ReactInstanceManager reactInstanceManager) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.testchannel.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
채널톡 floating 버튼을 보여주고 싶은 뷰 코드에서
아래 코드를 입력 하면 정상 작동된다.
import { ChannelIO } from 'react-native-channel-plugin';
let settings = {
"pluginKey": 'api pugin key',
"channelButtonOption": {
"xMargin": 16,
"yMargin": 16,
"position": 'right', // 'left', 'right'
}
}
ChannelIO.boot(settings).then((result) => {
console.log(result)
})
ChannelIO.showChannelButton();
추가 사항
[!] CocoaPods could not find compatible versions for pod "ChannelIOSDK":
In Podfile:
ChannelIOSDK (from `https://mobile-static.channel.io/ios/latest/framework.podspec`)
Specs satisfying the `ChannelIOSDK (from `https://mobile-static.channel.io/ios/latest/framework.podspec`)` dependency were found, but they required a higher minimum deployment target.
Aborting run
An unexpected error was encountered. Please report it as a bug:
위와 같은 에러 발생시
현재 ChannelIOSDK의 경우, minimum deployment target이 11 이상으로 변경 Podfile의 상단에
platform :ios, '13.0'
부분의 '13.0' 숫자가 11 이상이 되도록 변경해주시면 정상적으로 pod install이 가능하다고 한다.