Expo
기존에는 expo-cli를 통해서 생성한 React Native 앱만 expo sdk를 사용할 수 있었다.
장점은 expo가 정제한 네이티브 모듈을 쉽게 갖다 쓸수 있다는 점이였지만, 모든 네이티브 모듈을 포함하고 있어서 용량이 큰게 단점이였다.
그런데 이 단점을 어느정도 해소시켜줄 unimodules이 나왔다.
네이티브 모듈을 위한 코드가 Expo의 자산인지라, flutter가 나왔을때 React Native를 위해 만든 네이티브 모듈 코드를 재사용하기 위해 Unimodules가 만들어진것으로 보이며 이를 이용하여 expo-cli로 만들지 않은 일반 React Native 앱에서도 필요한 네이티브 모듈만 따로 설치하여 Expo SDK를 사용할 수 있게되었다.
(이를 bare 방식이라 부른다. 기존처럼 expo 앱에 올릴수 있는건 managed 방식이라 부른다.)
리액트 네이티브에서 지원되는 유니모듈 리스트
https://docs.expo.io/versions/v32.0.0/bare/unimodules-full-list/
1 | # expo cli 설치 |
이후 프로젝트 폴더로 이동한 후 필요한 expo 모듈을 설치한다.
expo-sqlite
1 | npm install expo-sqlite |
이후 App.js 를 아래와 같이 수정한다. (expo-sqlite의 예제를 bare로 import하게 변경)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168mport React from 'react';
import { StyleSheet, Text, View, TextInput, TouchableOpacity } from 'react-native';
import { SQLite } from 'expo-sqlite';
import { Asset, Constants, FileSystem, Permissions } from 'react-native-unimodules';
const db = SQLite.openDatabase('db.db');
class Items extends React.Component {
state = {
items: null
};
componentDidMount() {
this.update();
}
render() {
const { done: doneHeading } = this.props;
const { items } = this.state;
const heading = doneHeading ? 'Completed' : 'Todo';
if (items === null || items.length === 0) {
return null;
}
return (
<View style={{ marginBottom: 16, marginHorizontal: 16 }}>
<Text style={styles.sectionHeading}>{heading}</Text>
{items.map(({ id, done, value }) => (
<TouchableOpacity
key={id}
onPress={() => this.props.onPressItem && this.props.onPressItem(id)}
style={{
backgroundColor: done ? '#1c9963' : '#fff',
borderColor: '#000',
borderWidth: 1,
padding: 8
}}>
<Text style={{ color: done ? '#fff' : '#000' }}>{value}</Text>
</TouchableOpacity>
))}
</View>
);
}
update() {
db.transaction(tx => {
tx.executeSql(
`select * from items where done = ?;`,
[this.props.done ? 1 : 0],
(_, { rows: { _array } }) => this.setState({ items: _array })
);
});
}
}
export default class App extends React.Component {
state = {
text: null
};
componentDidMount() {
db.transaction(tx => {
tx.executeSql(
'create table if not exists items (id integer primary key not null, done int, value text);'
);
});
}
render() {
return (
<View style={styles.container}>
<Text style={styles.heading}>SQLite Example</Text>
<View style={styles.flexRow}>
<TextInput
style={styles.input}
placeholder="what do you need to do?"
value={this.state.text}
onChangeText={text => this.setState({ text })}
onSubmitEditing={() => {
this.add(this.state.text);
this.setState({ text: null });
}}
/>
</View>
<View style={styles.listArea}>
<Items
done={false}
ref={todo => (this.todo = todo)}
onPressItem={id =>
db.transaction(
tx => {
tx.executeSql(`update items set done = 1 where id = ?;`, [id]);
},
null,
this.update
)}
/>
<Items
done={true}
ref={done => (this.done = done)}
onPressItem={id =>
db.transaction(
tx => {
tx.executeSql(`delete from items where id = ?;`, [id]);
},
null,
this.update
)}
/>
</View>
</View>
);
}
add(text) {
db.transaction(
tx => {
tx.executeSql('insert into items (done, value) values (0, ?)', [text]);
tx.executeSql('select * from items', [], (_, { rows }) =>
console.log(JSON.stringify(rows))
);
},
null,
this.update
);
}
update = () => {
this.todo && this.todo.update();
this.done && this.done.update();
};
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#fff',
flex: 1,
paddingTop: Constants.statusBarHeight,
},
heading: {
fontSize: 20,
fontWeight: 'bold',
textAlign: 'center'
},
flexRow: {
flexDirection: 'row'
},
input: {
borderColor: '#4630eb',
borderRadius: 4,
borderWidth: 1,
flex: 1,
height: 48,
margin: 16,
padding: 5
},
listArea: {
backgroundColor: '#f0f0f0',
flex: 1,
paddingTop: 16
},
sectionHeading: {
fontSize: 18,
marginBottom: 8
},
});
출처 : https://raw.githubusercontent.com/expo/sqlite-example/master/App.js
이후 iOS를 실행하기 위해선 pod install을 해줘야한다. (unimodules 관련 패키지가 깔리는게 보인다)1
2
3
4cd ios
pod install
cd ..
npm run ios
안드로이드의 경우 MainApplication에 SQLitePackate()를 포함시켜줘야한다.1
2
3
4
5
6import expo.modules.sqlite.SQLitePackage;
private final ReactModuleRegistryProvider mModuleRegistryProvider = new ReactModuleRegistryProvider(Arrays.asList(
// Your other packages will be here
new SQLitePackage()
), Arrays.asList());
expo-web-browser
1 | npm install expo-web-browser |
마찬가지로 모듈 설치 후 MainApplication을 수정한다.
1 | import expo.modules.webbrowser.WebBrowserPackage; |
하지만 안드로이드의 경우 에러메시지를 내면서 빌드가 되지 않는다. 에러메시지를 자세히 보면1
2
3
4
5
6
7
8Caused by: com.android.builder.dexing.DexArchiveBuilderException: Error while dexing.
The dependency contains Java 8 bytecode. Please enable desugaring by adding the following to build.gradle
android {
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}
}
위와 같은 내용이 나오므로, app/build.gradle 위의 compileOptions를 추가하도록 하자.
그러면 빌드 에러나는것도 해결이 된다.
출처
댓글