必要な条件
このチュートリアルでは, QRコードの生成や読み取る事が出来るAndroid アプリを作っていきたいと思います。 チュートリアルに沿っていくには、次の条件が必要になります:
テスト用のAndroidスマホ
Visual Studio Code(他のIDEでも良い)
Node (npm)
Reactの基礎知識
準備
Expo CLI
パソコンのコマンドラインでExpo CLIをインストールしましょう:npm install -g expo-cli
。アカウントを持っていればexpo login
を実行します。アカウントを持っていなければ、expo register
を実行します。
Expoアプリ
AndroidスマホでExpoアプリをダウンロードします。ダウンロードが終わってから、アプリを開きます。「Profile」タブでログインが出来ます。
アプリ作成
好きなIDEのターミナルで次のコードを実行します:expo init expo-qrcode
。「Choose a template」が表示される時に「blank」を選びます。
cd expo-qrcode
を実行して、必要なパッケージをインストールします:npm i expo-barcode-scanner @react-navigation/stack @react-navigation/native react-native-qrcode-svg
npm start
を実行します。Expoアプで、「Scan QR Code」をクリックして、http://localhost:19002/ で表示されているQRコードをスキャンします。ダウンロードが終わってから、スマホでアプリが開きます。
開発中、コードを変更する時にスマホで表示されるまでに時間が掛かる可能性があります。その場合には、http://localhost:19002/ で「Run in web browser」をクリックするとパソコンのブラウザーで、アプリの様子が確認できます。
App.jsx
App.jsxのコードをすべてを削除し、以下のコードに置き換えます。
import React from "react";
import { createStackNavigator } from "@react-navigation/stack";
import { NavigationContainer } from "@react-navigation/native";
import Home from "./screens/Home";
import Scanner from "./screens/Scanner";
import Generator from "./screens/Generator";
//スタックナビゲーターのおかげで、画面間の移動ができます
const Stack = createStackNavigator();
function App() {
return (
<Stack.Navigator>
<Stack.Screen name="ホーム" component={Home} />
<Stack.Screen name="スキャナー" component={Scanner} />
<Stack.Screen name="生成" component={Generator} />
</Stack.Navigator>
);
}
export default () => {
return (
<NavigationContainer>
<App />
</NavigationContainer>
);
};
ホーム画面
プロジェクトのルートで、screensフォルダを作りましょう。そのフォルダで、Home.jsxを作ります。
import React from "react";
import { StyleSheet, Text, View, Pressable } from "react-native";
import { useNavigation } from "@react-navigation/native";
export default function Home() {
const navigation = useNavigation();
return (
<View style={styles.container}>
{QRコードスキャナー画面に移動}
<Pressable
onPress={() => navigation.navigate("スキャナー")}
style={styles.button}
>
<Text style={styles.text}>QRコードを読み取る</Text>
</Pressable>
{QRコード生成画面に移動}
<Pressable
onPress={() => navigation.navigate("生成")}
style={styles.button}
>
<Text style={styles.text}>QRコードを生成する</Text>
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
button: {
backgroundColor: "cyan",
borderRadius: 4,
paddingVertical: 10,
paddingHorizontal: 20,
margin: 20,
elevation: 3,
},
text: {
fontSize: 16,
lineHeight: 21,
fontWeight: "bold",
letterSpacing: 0.25,
color: "whitesmoke",
},
});
スキャナー
まだscreensフォルダで、Scanner.jsxを作ります。
import React, { useState, useEffect } from "react";
import { Text, View, StyleSheet, Pressable, Linking } from "react-native";
import { BarCodeScanner } from "expo-barcode-scanner";
export default function Scanner() {
//アプリはカメラを使う許可が認められるかどうか
const [hasPermission, setHasPermission] = useState(null);
//アプリはQRコードをスキャンしたかどうか
const [scanned, setScanned] = useState(false);
//最初のレンダリングで、カメラの許可を要求する
useEffect(() => {
(async () => {
const { status } = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(status === "granted");
})();
}, []);
//QRコードがスキャンされると、読み取ったリンクを開く
//リンクを開く事がでない場合にはメッセージを表示する
const handleBarCodeScanned = ({ data }) => {
Linking.openURL(data)
.then(() => setScanned(true))
.catch((err) => {
setScanned(true);
alert("リンクを開く事ができませんでした。");
});
};
return (
<View style={styles.container}>
{/* カメラアにクセスすることがまだ許可も拒否もされていない場合 */}
{hasPermission === null && <Text>カメラの許可を要求しています。</Text>}
{/* カメラアにクセスすることが拒否されている合 */}
{hasPermission === false && <Text>カメラにアクセスできません</Text>}
{/* カメラアにクセスすることが許可されている場合 */}
{hasPermission && (
<BarCodeScanner
barCodeTypes={["qr"]}
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
style={StyleSheet.absoluteFillObject}
/>
)}
{/* スキャンが終わってから表示する */}
{scanned && (
<Pressable onPress={() => setScanned(false)} style={styles.button}>
<Text style={styles.text}>別のQRコードを読み取る</Text>
</Pressable>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
},
button: {
backgroundColor: "cyan",
borderRadius: 4,
paddingVertical: 10,
paddingHorizontal: 20,
margin: 20,
elevation: 3,
},
text: {
fontSize: 16,
lineHeight: 21,
fontWeight: "bold",
letterSpacing: 0.25,
color: "whitesmoke",
},
});
QRコードの生成
/screens/Generator.jsxを作っていきましょう。
import React, { useState } from "react";
import { StyleSheet, Text, View, TextInput, Pressable } from "react-native";
import QRCode from "react-native-qrcode-svg";
export default function Generator() {
//QRコードになるリンク
const [qrCodeValue, setQrCodeValue] = useState("");
//入力されたテキスト
const [inputText, onChangeInputText] = useState("");
//inputTextが空白ではなければ、
//qrCodeValueを入力されたテキストに設定する
const generateQrCode = () => {
if (!inputText) {
alert("リンクを入力してください");
return;
}
setQrCodeValue(inputText);
};
return (
<View style={styles.container}>
<Text>リンクを入力してください</Text>
<TextInput
style={styles.input}
value={inputText}
onChangeText={onChangeInputText}
/>
<Pressable style={styles.button} onPress={generateQrCode}>
<Text style={styles.buttonText}>バーコードを生成する</Text>
</Pressable>
{/* qrCodeValueは空文字列でなければ、QRコードを表示する */}
{qrCodeValue ? <QRCode value={qrCodeValue} /> : <Text></Text>}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
input: {
height: 40,
marginHorizontal: 12,
marginVertical: 20,
borderWidth: 1,
padding: 10,
width: 200,
backgroundColor: "white",
},
button: {
backgroundColor: "cyan",
borderRadius: 4,
paddingVertical: 10,
paddingHorizontal: 20,
marginBottom: 40,
elevation: 3,
},
buttonText: {
fontSize: 16,
lineHeight: 21,
fontWeight: "bold",
letterSpacing: 0.25,
color: "whitesmoke",
},
});
デバッグ
開発中、次のエラーが発生しました。同じエラーが発生すれば、解決策の手順に従って下さい。
エラー:RNGestureHandlerRootView" was not found in the UIManager
解決策:
expo install react-native-gesture-handler
- App.jsxに
import 'react-native-gesture-handler';
を追加する
最後に
これで、QRコードの生成や読み取ることができるAndroid アプリが完了です。Androidスマホで、QRコードを読み取るや生成してみてください!