React.jsで作ったスライドショーアプリをCordovaでネイティブアプリ化しました。ƪ(•◡•ƪ)
いくつかハマった点があったのでまとめておきます。
なお、アプリ化の手順に関しては以下のサイトが大変参考になりました。♪(・ω・)ノ
Cordovaの導入やコマンドの使い方に関してはこのあたり
ハマった点… ><
react-routerを使ったときに起動ページのパスが違う
対策
各環境ごとに起動ページのパスが違うのでルーティングを複数用意する必要があります。
起動ページのパス | |
---|---|
React.jsアプリ | / |
cordova serve ios | /ios/www/index.html |
cordova emulate ios | /Users/xxx/Library/Developer/CoreSimulator/De…25B7D/CordovaReactSlickExample.app/www/index.html |
なので、react-routerを使うときは
<Router> <Route exact path="/" component={App} /> <!-- Reactのwebアプリでの確認用 --> <Route path="*/index.html" component={App} /> <!-- cordovaアプリ用 --> </Router>
のように2種類の初期ページ表示用のルーティングをもっておく必要がありました。
public/以下のassetsへのアクセス
これに関連して、React.jsアプリのpublic以下のassetsへの参照も少し工夫する必要がありました。
初期ページを起動時パス取得用のダミーページ(
Home
コンポーネント)にする<Router> <Route exact path="/" component={Home} /> <Route path="*/index.html" component={Home} /> </Router>
ダミーページで起動時のパスを取得し、Globalな state に保存する
class Home extends React.Component { constructor(props) { super(props) } componentDidMount() { // 起動時のパスを取得する const root = path.dirname(this.props.location.pathname) // stateに保存するアクションを呼ぶ this.props.setRootPath(root) } render() { // 実際の初期ページへリダイレクトする return ( <Redirect to="/login" /> ) } } const mapDispatchToProps = dispatch => { return { setRootPath: (path) => dispatch(setRoot(path)) // 起動時パスを保存するアクション } } export default connect(null, mapDispatchToProps)(Home)
assetsにアクセスするときは起動時パスを考慮した形で行う
const root = getState().home.root // 起動時のパスをstateから取得 const url = `${root === '/' ? '' : root}/images/slick/pictures.json` fetch(url)
Fetch API cannot load file:///android_asset/www/xx/xxx.json. URL scheme “file” is not supported のエラーが出た(Android)
対策
fetchは file:// をサポートしてないらしく XMLHttpRequest を使って記述します。
https://github.com/github/fetch/pull/92#issuecomment-140665932
function fetchLocal(url) { return new Promise(function(resolve, reject) { var xhr = new XMLHttpRequest xhr.onload = function() { resolve(new Response(xhr.responseText, {status: xhr.status})) } xhr.onerror = function() { reject(new TypeError('Local request failed')) } xhr.open('GET', url) xhr.send(null) }) }
fetchをfetchLocalに置き換えればok。
このエラーはiOSのときには出ませんがfetchLocal置き換えの副作用はありません。
Unable to post message to https://www.youtube.com. Recipient has origin file://.のエラーが出た
対策
config.xml に以下を追加
<allow-navigation href="https://*youtube.com/*" />
https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-whitelist/