Expo(React NativeのWebView)を使ってA-Frame ARアプリ作成してみました
A-FrameでARアプリを作成してみましたので、作成方法をご紹介します。
インターネット上の情報を色々と参考にさせてもらい実施しました。
ARというと、ネイティブ形式が主流かもしれませんが、試作を行うのに簡単に試してみたい等であれば、A-FrameのWeb形式でも要件を満たすかもしれません。
こったことはしておらず、基本的な流れですが、何かの参考になれば幸いです。
前提として、以下がありますので、ご注意ください。
- 動作確認の構成
- PC: M1 Mac
- OS: 11.4
- SW
- Expo: 4.7.2
- Xcode: 12.5.1
- A-Frame: 1.2.0
- AR.js: 3.3.3
- スマートデバイス: iPhone 7
- OS: 14.6
- 2021年7月頃に調べたり動作確認した内容です。
Androidはまだ動作しないのでご注意ください(ユーザ許可設定が正しくできていないようか気がしています)
本ブログの要点的な内容を最初に乗せると以下の流れになりました。
1. A-Frame AR.jsのブラウザ版を作成・確認
最初は、A-FrameでARをするため、インターネット上に情報が多いAR.jsによるブラウザ版を作成しました。(まだネイティブのARアプリではないです)
情報が古いものを活用しているかもしれませんが、まずは動くものを用意するということで、ご了承ください。
まずはA-Frameの情報を参照しました。
A-Frameサイト:https://aframe.io/
GitHub:https://github.com/aframevr/aframe/
ライセンス:MIT License:https://github.com/aframevr/aframe/blob/master/LICENSE
AR.jsサイト:https://ar-js-org.github.io/AR.js-Docs/
GitHub:https://github.com/AR-js-org/AR.js
ライセンス:MIT License:https://github.com/AR-js-org/AR.js/blob/master/LICENSE
どなたかの簡単に動作させた記事が手っ取り早く試すのには参考になるので、インターネットで検索して、以下等を参照させてもらいました。
https://j-xaas.github.io/ar-js-x-a-frame-WebAR%E5%85%A5%E9%96%80/
https://ar-js-org.github.io/AR.js-Docs/#getting-started
Marker Based Example
上記の「Marker Based Example」のコードを活用させてもらい、少しだけ恐竜を回転させました。
あとテキストと箱も入れてみました。
<!DOCTYPE html>
<html>
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<!-- we import arjs version without NFT but with marker + location based support -->
<script src="https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar.js"></script>
<body style="margin : 0px; overflow: hidden;">
<a-scene embedded arjs>
<a-marker preset="hiro">
<a-text value="this is text." position="-2 0 0" align="center" rotation="-90 0 0" color="#4CC3D9"></a-text>
<a-box position="2.0 0.0 0.0" rotation="0 45 0" color="#4CC3D9" shadow></a-box>
<a-entity
position="0 0 0"
scale="0.04 0.04 0.04"
rotation="-45 0 -45"
gltf-model="https://arjs-cors-proxy.herokuapp.com/https://raw.githack.com/AR-js-org/AR.js/master/aframe/examples/image-tracking/nft/trex/scene.gltf"
></a-entity>
</a-marker>
<a-entity camera></a-entity>
</a-scene>
</body>
</html>
実際の表示は以下のような画像になりました。
今回は、以下のような感じで、ペーパーレス(マーカーを印刷せずに)でテストをしました。
- Hiroマーカーは上記サイト上( https://raw.githubusercontent.com/AR-js-org/AR.js/master/data/images/hiro.png )から拝借しました。
- Hiroマーカーをフォトビューアー等で表示し、OBS Studioの仮想カメラソフトを使って、マーカーをカメラに写るように設定して仮想カメラを開始しておきます。(Windows PCに付属カメラがついている場合はデバイスマネージャから無効化する必要がありました)
- PCのChromeブラウザで、上記のhtmlファイルを表示し、マーカー上にARオブジェクトが表示されることを確認します。
あと、スマートデバイスのブラウザでも表示できることを、以下の流れで確認しました。
- AWS S3にhtmlファイルを配置
- S3 htmlファイルの署名付き一時URLを生成
- iPhoneのSafariやChromeから上記の署名付き一時URLにアクセス
- PCのHiroマーカーを映して確認
ざっと、A-FrameとAR.jsでAR表示ができました。
AR.jsには、ロケーションベース等、マーカー以外の機能もあるので今後試して見たいと思います。
2. Expo WebViewアプリを作成・確認
次に、ExpoのWebViewでARを表示するアプリを作成します。
上記で試したhtmlを活用していきます。
WebViewには、ソースを指定する形式に以下の種類がありました。
https://docs.expo.dev/versions/latest/sdk/webview/
- html形式
<WebView style={styles.container} originWhitelist={['*']} source={{ html: '<h1><center>Hello world</center></h1>' }} />
- uri形式
<WebView style={styles.container} source={{ uri: 'https://expo.dev' }} />
試したところ、html形式で、htmlファイルの内容をプログラム内に埋め込んでも、エラーとなり、カメラが正常に動作していないようでした。
「httpsスキーマを使わないと正常に動作しない」という情報をインターネットで目にしたので、uri形式で進めました。
ユーザ許可設定周りも確認したかったので、スタンドアロンアプリとして、M1 MacからiPhoneへアプリをインストールして動作を確認しました。
インストール手順については、以下の過去記事を参照してください。
(Expo使っているなら、Expo Goを使ってアプリを起動するのが通常かと思いますが。。。)
https://qiita.com/k-hideo/items/6aff1c187e53addd1550
動作確認を検証していてわかったのですが、WebViewでカメラを使う場合、NSCameraUsageDescriptionとは別に、NSMicrophoneUsageDescriptionのマイクも必要でした。
マイクがないと以下のエラーメッセージが表示されます。
Webcam Error
Name:
Message: WebRTC issue-!
navigator.mediaDevices not present in your browser
ただ、マイク設定も必要なのは、もしかしたら最新や今後改善されているかもしれません。(こちらのスレッドにこの件についてのやり取りがありました)
それで、WebViewのuri形式を使い、S3の署名付き一時URLを指定して確認したところ、カメラ映像は表示されるのですが、AR表示がうまくいきませんでした。
以下のような、静止画にARオブジェクトが表示されるような感じになってしまいました。(映像は表示されるがARオブジェクトが表示されない。AR表示されるが静止画となり映像とはならない、という感じでどっちつかずでした)
Chromeだと正常に表示できるのになぜだろうと、ちょっとWebViewのリファレンスを調べてみると、allowsInlineMediaPlaybackオプションが説明文的や挙動的に怪しい気がしたので、
さらにallowsInlineMediaPlaybackをキーワードに検索してみると、試す価値がありそうでしたので、やってみました。
結果としては、うまく改善されて以下のようにARオブジェクトの表示ができるようになりました。
参考までに以下にコードやイメージ、ビルド等の実行コマンドを載せておきます。
- ビルド コマンド類(viで作成するファイルの中身は、下のコード類を参照ください。)
expo init ex-webview-ar-1 Choose a template: › minimalを指定 expo install react-native-webview expo install react-navigation expo install react-navigation-stack react-navigation-tabs react-native-gesture-handler react-native-reanimated expo install react-native-screens react-native-safe-area-context vi app.json mkdir screens vi screens/PageHtml1.js vi screens/PageUri1.js vi screens/PageUri2.js vi screens/PageUri3.js vi screens/PageTop1.js vi App.js npm install arch -x86_64 npx pod-install arch -x86_64 npx expo prebuild Xcodeでファイルを開きビルド・デプロイし動作を確認
- コード類 (うまく転記できていない部分等ありましたらすみません。記法の関係上かインデント等が崩れている部分があります)
app.json (ここをクリックするとコードが以下に表示されます)
{ "expo": { "name": "ex-webview-ar-1", "slug": "ex-webview-ar-1", "version": "1.0.0", "assetBundlePatterns": [ "**/*" ], "ios": { "supportsTablet": true, "bundleIdentifier": "com.k-hideo.ex-webview-ar-1", "infoPlist": { "NSCameraUsageDescription": "ARのためカメラを使用します", "NSMicrophoneUsageDescription": "ARのためカメラとセットでマイクを使用します" } }, "android": { "package": "com.h_hideo.ex_webview_ar_1" } }, "name": "ex-webview-ar-1" }
screens/PageHtml1.js html形式でA-Frame AR.jsを記述しています。この場合、カメラが正常に動作しませんでした (ここをクリックするとコードが以下に表示されます)
import * as React from 'react'; import { WebView } from 'react-native-webview'; export default class PageHtml1 extends React.Component { render() { return ( <WebView originWhitelist={['*']} source={{ html: ` <!DOCTYPE html> <html> <script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script> <!-- we import arjs version without NFT but with marker + location based support --> <script src="https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar.js"></script> <body style="margin : 0px; overflow: hidden;"> <a-scene embedded arjs> <a-marker preset="hiro"> <a-text value="this is text." position="-2 0 0" align="center" rotation="-90 0 0" color="#4CC3D9"></a-text> <a-box position="2.0 0.0 0.0" rotation="0 45 0" color="#4CC3D9" shadow></a-box> <a-entity position="0 0 0" scale="0.04 0.04 0.04" rotation="-45 0 -45" gltf-model="https://arjs-cors-proxy.herokuapp.com/https://raw.githack.com/AR-js-org/AR.js/master/aframe/examples/image-tracking/nft/trex/scene.gltf" ></a-entity> </a-marker> <a-entity camera></a-entity> </a-scene> </body> </html> ` }} style={{ marginTop: 20 }} allowsInlineMediaPlayback={true} /> ); } }
screens/PageUri1.js uri形式でA-FrameサイトのトップページのURIを指定しています。A-Frameサイトは正常に開けました (ここをクリックするとコードが以下に表示されます)
import * as React from 'react'; import { WebView } from 'react-native-webview'; export default class PageUri1 extends React.Component { render() { return ( <WebView originWhitelist={['*']} source={{ uri: `https://aframe.io/` }} style={{ marginTop: 20 }} /> ); } }
screens/PageUri2.js uri形式でURIを入力できるようにしています、A-Frame AR.jsのページを入力すると正常に動作しました (ここをクリックするとコードが以下に表示されます)
import * as React from 'react'; import { View, Text, TextInput} from 'react-native'; import { WebView } from 'react-native-webview'; export default class PageUri2 extends React.Component { constructor(props) { super(props); this.state = { text: "https://aframe.io/", debug: "", }; } render() { let webViewRef; return ( <View style={{flex:1}}> <Text></Text> <Text></Text> <TextInput style={{ width: "100%", borderBottomWidth: 1, borderBottomColor: "#ccc" }} onChangeText={(text) => { this.setState({text}); console.log("before reload."); this.state.debug = " before reload. "; if (this.webViewRef) { console.log("do reload."); this.state.debug += " do reload. "; //console.log(this.webViewRef); this.webViewRef.reload(); } console.log("after reload."); this.state.debug += " after reload. "; }} value={this.state.text} /> <Text>{this.state.text}</Text> <Text>{this.state.debug}</Text> <WebView ref={this_ref => (this.webViewRef = this_ref)} originWhitelist={['*']} source={{ uri: this.state.text }} //source={{ uri: `https://aframe.io` }} style={{ marginTop: 20 }} allowsInlineMediaPlayback={true} /> </View> ); } }
screens/PageUri3.js uri形式でA-Frame AR.jsのページを指定してます。こちらも正常に動作しました (ここをクリックするとコードが以下に表示されます)
import * as React from 'react'; import { WebView } from 'react-native-webview'; export default class PageUri3 extends React.Component { render() { return ( <WebView originWhitelist={['*']} source={{ uri: `https://bucket.s3.amazonaws.com/src/ar-1.2.0.html?AWSAccessKeyId=key&Signature=sig&Expires=1630940983` }} style={{ marginTop: 20 }} allowsInlineMediaPlayback={true} /> ); } }
screens/PageTop1.js 上記のhtml形式やuri形式のページに遷移するトップページです (ここをクリックするとコードが以下に表示されます)
import React, { Component } from 'react'; import { Text,View,Button } from 'react-native'; export default class PageTop1 extends Component { render() { return ( <View> <Button title="go to html 1" onPress={() => { this.props.navigation.navigate('PageHtml1') }} /> <Button title="go to uri 1: a-frame top" onPress={() => { this.props.navigation.navigate('PageUri1') }} /> <Button title="go to uri 2: any uri" onPress={() => { this.props.navigation.navigate('PageUri2') }} /> <Button title="go to uri 3: specify uri" onPress={() => { this.props.navigation.navigate('PageUri3') }} /> </View> ) } }
App.js (ここをクリックするとコードが以下に表示されます)
import React, { Component } from 'react'; import { createAppContainer } from 'react-navigation'; import { createStackNavigator } from 'react-navigation-stack'; import PageTop1 from './screens/PageTop1'; import PageHtml1 from './screens/PageHtml1'; import PageUri1 from './screens/PageUri1'; import PageUri2 from './screens/PageUri2'; import PageUri3 from './screens/PageUri3'; const MainStack = createStackNavigator( { PageTop1: PageTop1, PageHtml1: PageHtml1, PageUri1: PageUri1, PageUri2: PageUri2, PageUri3: PageUri3, } ) const AppContainer = createAppContainer(MainStack) export default class App extends Component { render() { return ( <AppContainer /> ) } }
-
イメージ類
3. さいごに
色々(Mac、ReactNative、Expo)と初心者のため、いくつものエラーが発生しまして、グーグル先生に何度もお世話になりながら、基本的なことですが、なんとか表示できるようになりました。これもみなさんが情報を残してくれているおかげですね。感謝感謝です。
もちろん社内の人にも情報を教えてもらったりしました。感謝感謝です。
A-Frame AR.jsをネイティブアプリで稼働させることにニーズが少ないかもしれませんが、選択肢の一つとなればよいのかと思います。
ひとまず基本的な方式の一つが動かせれるようになったので、今後時間と機会があれば、他の方式や、もうちょっと凝ったこともやってみたいと思います。
Author And Source
この問題について(Expo(React NativeのWebView)を使ってA-Frame ARアプリ作成してみました), 我々は、より多くの情報をここで見つけました https://qiita.com/k-hideo/items/6d02339c3f3dc56e7a19著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .