React Native uygulamasının kütüphane haline getirilmesi

Zafer Ayan
Fiba Tech Lab
Published in
8 min readJun 19, 2021
React Native Android uygulamasını Github Packages üzerinden yayınlama

Mevcut React Native uygulamanızda yer alan bir iş akışınızı, başka uygulamalar ile de paylaşmak için, uygulamanın bir kısmını library haline getirmek isteyebilirsiniz. Native tarafta library oluşturma ve yönetme işleminin, normal uygulama geliştirimine göre bazı zorlukları bulunurken, ek olarak bir de React Native ile entegre çalışacak şekilde bir ürün ortaya çıkarmak kafa karıştırıcı ve yorucu bir süreç haline gelebiliyor. İnternette arama yaptığınızda da kaynaklar yetersiz kalabiliyor. Bu nedenle, tam bu durumu çözmek için pek çok kaynaktan edindiğim bilgileri birleştirerek sizlere aktarmaya çalışacağım. Hazırsanız başlayalım.

Mevcut React Native projesinin klonunun yapılması

Projedeki sadece bir iş akışını kütüphane haline getireceğimiz için projenin aynı konfigürasyonlarına sahip bir klonunu oluşturup kodun bir kısmını klon projeye aktarmak gerekiyor.

Bunun için sıfırdan bir React Native projesi oluşturalım. Örneğin React Native 0.62.2 kullanılıyorsa siz de aşağıdaki komutla projenizi oluşturmalısınız:

npx react-native init SampleRNAppFlowLibrary --version 0.62.2

Devamında ise RN içerisinde kullandığınız kütüphaneleri eklemeniz gerekiyor. Bu projede, native bir bağımlılık olarak örnek olması açısından react-native-video kütüphanesini kullanacağım:

yarn add react-native-video

Şimdi bir video görüntülemek için App.js’in içine gelelim ve aşağıdaki gibi değiştirelim:

import React from 'react';
import {StyleSheet} from 'react-native';
import Video from 'react-native-video';

const App = () => {
return (
<Video
source={{
uri: 'http://techslides.com/demos/sample-videos/small.mp4',
}}
resizeMode="contain"
style={styles.backgroundVideo}
/>
);
};
var styles = StyleSheet.create({
backgroundVideo: {
width: '100%',
height: '100%',
},
});

export default App;

Sonrasında uygulamayı android simulatörde çalıştıralım:

yarn run android
Bu haliyle çok basit ve sadece video görüntüleyen bir RN projesi haline getirdik.

Şimdi proje alt bağımlılıklarını Github Packages üzerine atmamız gerekiyor. Bunun için Github üzerinden bir personal access token oluşturmak şart. Haydi acccess token’ımızı oluşturalım.

Github’dan Personal Access Token alınması

Github üzerinden Access token oluşturmak için aşağıdaki adımları izlemek gerekiyor. Öncelikle github.com’a gidelim ve sağ üstteki profil fotoğrafımıza tıklayıp Settings’e gelelim:

  • Devamında sol panelden Developer Settings’i seçelim:
  • Çıkan ekranda, sol kısımda yer alan Personal access tokens’ı seçelim ve sağdan Generate new token butonuna tıklayalım:

Sonrasında parolanızı girmenizi isteyen bir ekran çıkacak. Burada parolamızı doğruladıktan sonra aşağıdaki gibi bir ekran bizi karşılıyor. Burada Note kısmına oluşturacağımız access token’ın hangi amaçla kullanacağımıza dair bir ipucu bilgi girebiliriz. Örneğin “React Native kütüphanem” girilebilir.

Sonrasında token’ın hangi yetkilere sahip olması gerektiğini Select scopes bölümünden ayarlayacağız. Burada, Github packages’a kütüphane eklemek istedğimiz için write packages yetkisini vermemiz gerekiyor. Bu yetki, aynı zamanda repo ile ilgili diğer alt yetkileri de gerektirdiği için, otomatik olarak gereken alt yetkiler de seçilmiş olacaktır.

Devamında sayfanın en altına gelip Generate Token’ı işaretleyiniz:

  • Oluşan token’ı kopyalayıp bir dosyaya yazarak kaydedelim. Sonra işimize yarayacak.

Artık proje içerisinde tümleşik olarak yer alan react-native-video bağımlılığını paket haline getirip Github packages’ta yayımlayabiliriz.

React Native Projesindeki Android bağımlılıklarının Github Packages’ta yayımlanması

Android bağımlılıklarını birer maven paketi olarak yayınlamak için, Android Studio projesine gelip sol taraftaki proje menüsünden build.gradle (react-native-video)’yu seçelim:

dependencies {
implementation "com.facebook.react:react-native:+"
implementation 'com.yqritc:android-scalablevideoview:1.0.4'
}

Burada dependencies kısmında da görüleceği gibi react-native-video kütüphanesinin, react native ve scalablevideoview alt bağımlılıkları yer alıyor. Buradaki react native kütüphanesi, node_modules’ten çekildiği için yayınlama esnasında sorun çıkarabilir. Bunun yerine react-native’in paylaşıldığı uygun bir maven repo bulmak gerekiyor. Walmart’ın react native versiyonlarını yayımladığı repoyu kullanabiliriz:

https://mvnrepository.com/artifact/com.walmartlabs.ern/react-native

Ben projede React Native 0.62.2 kullanıyorum. Benzer şekilde dependencies kısmında walmart’ın react native kütüphanesini şu şekilde kullanabiliriz:

dependencies {
implementation 'com.walmartlabs.ern:react-native:0.62.2'
implementation 'com.yqritc:android-scalablevideoview:1.0.4'
}

Şimdi react-native-video için bir pom.xml oluşturarak Github packages’a atmak için Gradle’dan faydalanacağız. Bunun için build.gradle (react-native-video) dosyasının sonuna aşağıdaki gibi bir maven publish script’i ekleyelim.

Ayrıca Javascript dosyasını işlemek için JSC’ye (JavaScript Core VM) ihtiyacımız var. JSC halihazırda node_modules dizini içerisinde .aar dosyası olarak bulunuyor. Bu dosyayı maven’a atabiliriz. Ayrıca, jsc gibi halihazırda derlenmiş aar paketlerini de eklemeniz gerekiyorsa onun için de ayrı bir gradle task oluşturmalısınız. Son hali aşağıdaki gibi olacaktır (Burada react-native android paketini de packages’a yükledim):

Devamında sağdaki Gradle penceresinden react-native-video altındaki publish task’ini çalıştırabiliriz:

Paketlerin yayınlanması upload işlemlerinden dolayı zaman alabilir. BUILD SUCCESSFUL mesajını gördükten yaklaşık birkaç saniye sonra paketler aşağıdaki gibi eklenmiş olacaktır:

Projenizdeki diğer paketleri de benzer şekilde ekleyebilirsiniz.

Şimdi ise, github’a eklediğimiz paketleri proje içerisinde kullanmaya geçelim.Öncelikle, auto-linking’i kaldırıp bizim kütüphanelerimizi kullanmasını sağlayalım.

Auto-linking’in kaldırılması ve Github Packages’a eklenen paketlerin kullanımı

Auto-linking’in kaldırılması için android/settings.gradle dosyasında apply from file olan kısımları silelim ve sadece aşağıdaki gibi iki satır haline getirelim:

rootProject.name = 'SampleRNAppFlowLibrary'
include ':app'

build.gradle (Project) dosyasında dependencies kısmınına Github Packages reposunu ve ilgili user-token bilgilerimizi ekleyelim:

allprojects {
repositories {

google()
jcenter()
maven { url 'https://www.jitpack.io' }

maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/ozcanzaferayan/react-native-as-an-android-lib")
credentials {
username = 'ozcanzaferayan'
password = "ACCESS_TOKEN_DEĞERİ"
}
}
}
}

build.gradle (app) dosyasında da dependencies kısmına paketlerimizi kullanacak şekilde değiştirelim ve auto-linking’in kaldırılması için en alttaki apply from file satırını silelim.

dependencies {
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"

implementation 'com.walmartlabs.ern:react-native:0.62.2'
implementation 'com.zaferayan.integration:android-jsc-r245459:1.0.0'
implementation 'com.zaferayan.integration:react-native-video:1.0.0'

}
//apply from: file...

Şimdi MainApplication.java dosyasına gelelim ve auto-linking yerine paketlerin elle eklenmesini sağlayalım:

@Override
protected List<ReactPackage> getPackages() {
List<ReactPackage> packages = new ArrayList<>();
packages.add(new MainReactPackage(null));
packages.add(new ReactVideoPackage());

return packages;
}

Kütüphane haline getireceğimiz için flipper’a da ihtiyacımız olmayacak. Bu nedenle daha sade hale getirmek amacıyla debug dizinindeki ReactNativeFlipper.java dosyasını silelim (SampleRNAppFlowLibrary/android/app/src/debug/java/com/samplernappflowlibrary/ReactNativeFlipper.java).

Android studio üzerinden projeyi ayağa kaldırıp, yapılan değişikliklerin düzgün çalıştığına emin olalım. Sonraki aşamada oluşturduğumuz projeyi android kütüphanesi (maven dependency de denebilir) haline getireceğiz.

Projenin kütüphane haline getirilmesi

MainApplication içeriğinin MainActivity’e taşınması

Bir android library’sinde MainApplication.java dosyası bulunmadığından dolayı öncelikle bu dosyadaki içeriği MainActivity.java dosyasına taşımamız gerekiyor. MainActivity’nin son hali aşağıdaki gibi olmalıdır:

package com.samplernappflowlibrary;
import android.app.Activity;
import android.os.Bundle;
import com.brentvatne.react.ReactVideoPackage;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactPackage;
import com.facebook.react.ReactRootView;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends Activity {
private ReactRootView mReactRootView;
public static ReactInstanceManager mReactInstanceManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SoLoader.init(this, false);
mReactRootView = new ReactRootView(this);
List<ReactPackage> packages = new ArrayList<>();
packages.add(new MainReactPackage(null));
packages.add(new ReactVideoPackage());
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setCurrentActivity(this)
.setBundleAssetName("index.android.bundle")
.setJSMainModulePath("index")
.addPackages(packages)
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
mReactRootView.startReactApplication(mReactInstanceManager,
"SampleRNAppFlowLibrary",
null);
setContentView(mReactRootView);
}
}

Artık Application dosyası olmadığına göre şimdi AndroidManifest.xml dosyası içerisinde application tag’inin tüm satırlarını silelim ve android:usesCleartextTraffic=”true” ekleyelim. Ayrıca debug dizininde de ApplicationManifest.xml dosyası var, onu da silelim. AndroidManifest.xml’in son hali aşağıdaki gibi olmalıdır:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.samplernappflowlibrary">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:usesCleartextTraffic="true">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>

</manifest>

Şimdi projeyi tekrar çalıştığına emin olalım ve sonraki aşamaya geçelim.

build.gradle üzerinden projeyi library haline getirmek

Android uygulamasını library haline getirmek için build.gradle (app) dosyasında 2 işlem yapmak gerekiyor:

  • android plugin’i yerine library plugini kullanmak.
  • applicationId’yi kaldırmak.

build.gradle(app) dosyasını açalım ve uygulamayı library’e dönüştürmek için:

apply plugin: "com.android.android"

yerine

apply plugin: "com.android.library"

haline getirelim. Ayrıca aşağıdaki applicationId’li satırı silelim

applicationId "com.samplernappflowlibrary"

Gereksiz yorum satırları da silindiğinde build.gradle’ın son hali aşağıdaki gibi olacaktır:

apply plugin: "com.android.library"
android {
compileSdkVersion rootProject.ext.compileSdkVersion

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
}
}

dependencies {
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"

implementation 'com.walmartlabs.ern:react-native:0.62.2'
implementation 'com.zaferayan.integration:android-jsc-r245459:1.0.0'
implementation 'com.zaferayan.integration:react-native-video:1.0.0'

}

index.js.bundle dosyasının ve proje içerisinde diğer görsellerin yer aldığı paketin oluşturulması

Javascript dosyasını ve diğer görsel dosyaları kütüphane içerisine dahil edebilmek için aşağıdaki komutu çalıştırmamız gerekiyor:

mkdir -p dist/app/src/main/{res,assets} && \
npx react-native bundle \
--platform android \
--dev false \
--entry-file index.js \
--bundle-output dist/app/src/main/assets/index.android.bundle \
--assets-dest dist/app/src/main/res

Bu sayede dist dizini oluşacak, ve içerisinde uygun yerlere kopyalanması gereken js ve görsel dosyaları yer alacaktır. Şimdi proje içerisinde android/app/src/main/ altına assets dizinini oluşturalım ve index.android.bundle dosyasını assets altına kopyalayalım. Ayrıca proje içerisinde kullandığınız fotoğraflar vs içerikler varsa onları da android/app/src/main/res/ dizini içerisine atmalısınız.

Kütüphanenin Github Packages üzerinden yayımlanması

Bundle ve ilgili görsel içerikler uygun konumlarına atıldıktan sonra , kütüphane haline getirdiğimiz uygulamayı artık Github’a atabiliriz. build.gradle(app)’in son hali aşağıdaki gibi olmalıdır:

apply plugin: "com.android.library"

android {
compileSdkVersion rootProject.ext.compileSdkVersion

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
}
}

dependencies {
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"

implementation 'com.walmartlabs.ern:react-native:0.62.2'
implementation 'com.zaferayan.integration:android-jsc-r245459:1.0.0'
implementation 'com.zaferayan.integration:react-native-video:1.0.0'

}

apply plugin: 'maven-publish'

def libVersion = '1.0.1'
def libGroupId = 'com.zaferayan.integration'
def libArtifactId = 'sample-rn-app-flow-library'

def repoUrl = 'https://maven.pkg.github.com/ozcanzaferayan/react-native-as-an-android-lib'
def repoName = "GitHubPackages"
def repoUsername = 'ozcanzaferayan'
def repoPassword = 'GITHUB_ACCESS_TOKEN' // Buraya Github üzerinden aldığınız değeri yapıştırın

project.afterEvaluate {
publishing {
publications {
library(MavenPublication) {
groupId libGroupId
artifactId libArtifactId
version libVersion
artifact bundleReleaseAar

pom.withXml {
def dependenciesNode = asNode().appendNode('dependencies')
configurations.implementation.allDependencies.each {
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
}
}
}
}

repositories {
maven {
name = repoName
url = uri(repoUrl)
credentials {
username = repoUsername
password = repoPassword
}
}
}
}
}

Yine sağdaki Gradle menüsünden publish edebilirsiniz. GitHub packages’ta aşağıdaki gibi listelenecektir.

Publish edilen React Native kütüphanesinin boş bir Android projesi içerisinde kullanımı

Github packages’a attığımız uygulamayı artık boş bir android projesi içerisinde sıfırdan kullanabiliriz. Devamında yine önceki adımlara benzer şekilde:

  1. build.gradle (project): Github packages reposunu ve access token bilgisini buraya ekleyebilirsiniz.
repositories {
google()
jcenter()
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/ozcanzaferayan/react-native-as-an-android-lib")
credentials {
username = 'ozcanzaferayan'
password = "ACCESS_TOKEN"
}
}
}

2. build.gradle (app): Yayınladığınız React native kütüphanesini buraya ekleyebilirsiniz.

dependencies {
...
implementation 'com.zaferayan.integration:sample-rn-app-flow-library:1.0.1'
...
}

3. MainActivity.java: Kütüphaneyi burada aşağıdaki gibi kullanabilirsiniz:

Intent intent = new Intent(this, com.samplernappflowlibrary.MainActivity.class);
startActivity(intent);

Uygulamayı ayağa kaldırdığınızda React Native activity’sinin de düzgün çalıştığını göreceksiniz.

Sonuç olarak

Bir React Native uygulamasını kütüphane haline getirip diğer native uygulamaların kullanacağı şekilde hazırlamak, herhangi düzgün bir tutorial olmadığı için zorlu olabiliyor. Bu yazıda RN uygulamasını bir şekilde kütüphane haline getirip size aktarmaya çalıştım. Bu adımlarda eksik/hatalı olduğunu düşündüğünüz kısımlar varsa bana ulaşabilirsiniz. Projenin bitmiş haline buradan erişebilirsiniz. Sonraki yazımda görüşmek üzere…

Kaynaklar:

--

--