著者アーカイブ 村上

村上 著者:村上

【Android】Mapboxで表示した地図の中心を変更する方法

昨日の予告通り、今回はMapboxの地図の中心位置を変更する方法についてです。
前回の記事については、下記から確認頂けます。

【Android】Mapboxを使って地図上にピンを立てる方法
https://cpoint-lab.co.jp/article/201810/【android】mapboxを使って地図上にピンを立てる方法/

 

では早速実装方法について。
なお、今回のコードは Mapbox が導入済みであることを前提に進めています。

まず onCreate() 内に、下記のコードを追加します。

mapView.getMapAsync(this);

ちなみに、この時、Android Studioでは、this の部分がエラーになり、赤い波下線が引かれますので、そこにカーソルを合わせて Alt + Enter を押します。
表示される対処法の項目中に、OnMapReadyCallbackimplements するというような内容の候補があるので、こちらを選択します。
すると、onMapReady() という関数がオーバーライドされるので、その中に下記のコードを追加します。

@Override
public void onMapReady(MapboxMap mapboxMap) {
    CameraPosition position = new CameraPosition.Builder()
            .target(new LatLng(lat, lng)) // Sets the new camera position
            .zoom(11) // Sets the zoom to level 10
            .tilt(0) // Set the camera tilt to 0 degrees
            .build(); // Builds the CameraPosition object from the builder

    mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(position), 1000);
}

ズームレベルや、傾きなどは適宜変更してください。
こちらを実行すると、起動後、カメラの位置が上記で指定した位置が中心になるように移動します。
処理としては以上で完了です。

 

意外と回りくどい方法だな…と思うのは私だけでしょうか…?
レイアウトファイルのXMLでは、地図の初期位置を簡単に指定できるので、コード上でも簡単にできてほしいですね。
ですが、意図していたことは実現できたので問題なし!
もし、同じことに取り組んでいる方は、参考にしていただければと思います。

村上 著者:村上

【Android】Mapboxを使って地図上にピンを立てる方法

今回は、Mapboxを使って、Androidアプリで地図を表示する方法について。
導入は簡単でしたので、今回はそれプラス、地図にマップピンを立てたいと思います。

導入は本家サイトをご参考ください。
なお、マップの表示にはアクセストークンが必要なため、ユーザー登録を行ってください。

Install Maps SDK for android|Mapbox
https://www.mapbox.com/install/android/

上記で紹介している手順通りにSDKの導入やPermissionの設定、MapViewの指定を行えば、問題なく地図が表示できるはずです。
で、地図が表示されたら、いよいよマップピン表示!

コードは下記のとおりです。
重複している箇所があるので、必要なところのみコピー&ペーストしてください。

private MapView mapView;
private MapboxMap mapboxMap;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Mapbox.getInstance(this, "[access_token]");
    setContentView(R.layout.activity_map);

    mapView = findViewById(R.id.mapView);
    mapView.onCreate(savedInstanceState);
    mapView.getMapAsync(this);

    Double lng = [緯度];
    Double lat = [経度];
    mapView.getMapAsync(mapboxMap -> mapboxMap.addMarker(new MarkerOptions()
            .position(new LatLng(lat, lng))
            .title("写真を撮影した場所")));
}

こちらを実行すると、下の写真のようにマップピンが地図上に表示されます。

会社で撮影した写真の位置情報を使用したので、若干の誤差はあれど、ほぼあっていますね!

 

以上、地図上にピンを立てる方法でした。
しかしこれだけだと、マップの中心位置≠マップピンが立っている場所、なので、マップの中心位置やピンの場所によっては、地図をかなりスワイプしたりドラッグする必要がある場合があります。
次回は、こちらを解消すべく、地図の中心位置をコード上で操作する方法についてご紹介できればと思います。

村上 著者:村上

【Cordova】Bluetoothをアプリから有効にする方法

今回は、Corodvaのプラグイン「BluetoothSerial」についてです。
こちらのプラグインは、iBeaconのプラグインを利用するために、インストールしました。

GitHubはこちらから。

GitHub – don/BluetoothSerial: Cordova (PhoneGap) Plugin for Serial Communication over Bluetooth
https://github.com/don/BluetoothSerial

現在、開発中のアプリに Beaconの受信機能を実装していますが、このBeaconを使うときは、BluetoothがONになっている必要があります。
ですが、人によっては、スマートフォンの Bluetooth を、使うときはONにして、いつもはOFFにしている場合もあるかと思います。
というか、まさに私がそのタイプ。
なので、アプリを起動したタイミングで、BluetoothがONになっているかを確認し、もしOFFだったら、ユーザーに確認してONにする、ということをやりました。

 

インストール方法については、下記のコマンドを実行するだけです。

cordova plugin add cordova-plugin-bluetooth-serial

さて、BluetoothをONにするためのコードはこちら。

bluetoothSerial.enable(function() {
    // Bluetoothが有効
    // その時の処理
}, function() {
    // ユーザーがBluetoothを有効にしなかった
    // その時の処理
});

こちらを実行すると、BluetoothがOFFの場合は、下の画像のようなダイアログが表示されます。

こうしておけば、Bluetoothの有効化を促すことができますね。
なお、既にONのときには何も起こりません。

ちなみに、ただONかOFFかだけを確認したい場合は、isEnabled を使います。
書き方は、下記のとおりです。

bluetoothSerial.isEnabled(function() {
    // BluetoothがON
    // その時の処理
}, function() {
    // BluetoothがOFF
    // その時の処理
});

メッセージでBluetoothの有効化を促したい場合などは、こちらの方法が使えると思います。

 

以上、Corodvaアプリから Bluetoothを有効にする方法でした。

村上 著者:村上

【Cordova】iBeaconとの推定距離を取得する方法【JavaScript】

試して分かりましたが、これは一筋縄ではいかないやつですね。
これに関しては、私にBeaconの知識がないのも原因でしょう。

ということで、早速本題へ。
今回、参考にさせていただいたサイトはこちらです。

RSSI と TxPower からビーコンとの距離および近接度(Proximity)を推定する – Qiita
https://qiita.com/shu223/items/7c4e87c47eca65724305

まず、ビーコンの信号から TxPower と RSSI という値を取得します。
ちなみに、それぞれの値は下記のようなものです。

  • TxPower:ビーコンが発する信号の強さ
  • RSSI:デバイス(AndroidやiOS端末)が受信した電波の強度

で、これらの値と距離との関係は、下記のような式で表すことができるとのこと。
なお、d は距離を表しています。

RSSI = TxPower - 20 * lg(d)

で、こちらの式から、距離 d の計算式は下記のとおりです。

 
d = 10 ^ ((TxPower - RSSI) / 20)

こちらの式をJavaScriptで書くとこうなります。

var d = Math.pow(10.0, (TxPower - RSSI) / 20.0

これで一応は、距離が取得できました。

 

こちらを実際に cordova-plugin-ibeacon に導入すると、下記のようになります。

delegate.didRangeBeaconsInRegion = function(pluginResult) {
    var beaconData = pluginResult.beacons[0];
    console.log("d = "+((Math.pow(10.0, (beaconData.tx - beaconData.rssi) / 20.0))));
}

ビーコンの信号が取得されている間、定期的に呼ばれる関数内で使用しています。
ちなみに、実際に取得できるデータはこちら。

{
    "eventType":"didRangeBeaconsInRegion",
    "region":{
        "identifier":"[ビーコンの名前]",
        "uuid":[ビーコンのUUID],
        "major":"1",
        "minor":"3",
        "typeName":"BeaconRegion"
    },
    "beacons":[
        {
            "uuid":[ビーコンのUUID],
            "major":"1",
            "minor":"3",
            "proximity":"ProximityNear",
            "rssi":-67,
            "tx":-58,
            "accuracy":1.7
        }
    ]
}

こちらを実行すると、ビーコンの信号を受信している間ずっと定期的に計算したビーコンとの距離が出力されていました。

が、参考にした記事によると、この値は「自由空間」という「障害物がない空間」での測定を前提とした計算方法らしいです。
障害物などの有無によって、電波の受信強度が変わるので、実際にはそのあたりも考慮する必要があるとのこと。
…はい、だんだん分からなくなってまいりました!

 

ということで、本日はいったんここまでとしたいと思います。
実際に取れた値も、やけに振れ幅が多いし…実際に使うにはまだまだでしょう。
もう少し、Beaconについての学習も進めていきたいと思います。

以上、Beaconとの距離を計算する方法でした。

村上 著者:村上

【React】外部関数の定義方法とその呼び出し方法

特に難しいことではないのですが、忘れそうなので備忘録として。
タイトル通り、Reactで関数を別ファイルで定義する方法と、その関数を呼び出す方法についてです。

参考にさせていただいたサイトはこちらから。

JavaScript – react 共通で使いたい関数(112279)|teratail
https://teratail.com/questions/112279

似たようなことを質問している方がいらっしゃったので、助かりました。

 

さて、まず関数の定義方法ですが、下記のように記述すると、外部から呼び出すことができます。

export default function [関数名]() {
  // 処理
}

なおこの時、1関数 1ファイルにしておくと、関数=ファイルとしてディレクトリで管理できるので便利とのことでした。

で、この関数を呼び出し、実行するときは、下記のとおりです。

// 関数の読み込み
import [任意の関数名] from '[ファイルの場所]'

// 関数の実行
[関数名]();

方法としては以上です!
あとは、指定した箇所で関数が実行されます。

 

簡単ですが、以上、関数の定義方法とその呼び出し方法でした。
export default という記述を忘れそうだと思ったので、こうしてまとめました。
うっかり忘れたときの自分のためのコピー元ですね。
もし、同じことをやりたいと思っている方がいらっしゃれば、参考にしていただければと思います。

村上 著者:村上

【Android】「Configuration on demand is not supported by the current version of the Android Gradle plugin since you are using Gradle version 4.6 or above.」の対処法

今回も、Android Studioでアプリを開発中に遭遇したエラーについてです。
最近、何だかエラー遭遇率が妙に高い気が…。
特に、変なところをいじってはいないはずなので、気のせいだと良いのですが。

さて、今回のエラーはこちら。

Configuration on demand is not supported by the current version of the Android Gradle plugin since you are using Gradle version 4.6 or above.

先日まで動いていはずなのですが、今日起動してビルドしようとしたところ、上記のようなエラーが出ました。
こちらをGoogle翻訳に掛けた結果は、「Gradleバージョン4.6以上を使用しているため、Android Gradleプラグインの現在のバージョンではオンデマンドでの設定はサポートされていません。」とのこと。
どうやらサポートされてない設定を使っているようでした。
…なぜ急に?

 

で、調べたところ下記の記事がヒットしました。

Configuration on demand is not supported by the current version of the Android Gradle plugin – Stack Overflow
https://stackoverflow.com/questions/49990933/configuration-on-demand-is-not-supported-by-the-current-version-of-the-android-g

この記事によると、まず、gradle.properties で指定している「org.gradle.configureondemand」という記述を削除します。
が、上記に該当する記述は見つからず…一旦、置いておくことに。

そして次に、Setting から、Build, Execution, Deployment > Compiler を開きます。

そうすると、下の方に「Configure on Demand」という箇所があるので、ここのチェックを外します。
上の画像だと、赤枠で囲っている場所です。
あとは、Apply を押してから、OKを押せば設定は完了です。
その後、いつも通りビルドを行ったところ、問題なくビルドが成功し、無事にアプリも実行できました。

 

以上、「Configuration on demand is not supported by the current version of the Android Gradle plugin since you are using Gradle version 4.6 or above.」エラーの対処法でした。
エラー文だけでは意味が分からなかったのですが、案外あっさりと解決できたので良かったです。
自分が書いたコード以外のところでエラーが出ると若干ヒヤッとしますね…。
もし同じエラーでお困りの方がいらっしゃいましたら、参考にしていただければと思います。

村上 著者:村上

【React】「react-router」でLinkタグを使わないページ遷移の方法

昨日の記事に引き続き、今回もReactでのページ遷移の方法について。
前回は、Linkタグでのページ遷移について書きましたので、今回は関数内でのページ遷移方法についてです。

ちなみに、前回の記事はこちらから。

【React】「react-router」でのページ遷移の実装方法

 

今回参考にさせていただいた記事はこちらから。

react-routerのページ遷移をhandleで行う時にはwithRouterを使う – Qiita
https://qiita.com/junara/items/a4a98c27dc23fd53ebb9

ベースとなるページは前回の記事で作成したものを、ほぼそのまま流用します。

import React from 'react'
import { BrowserRouter, Route, Link } from 'react-router-dom'
import Detail from './Detail'
 
const App = () => {
  return (
      <BrowserRouter>
        <div>
            <ul>
                <li><Link to='/'>Home</Link></li>
                <li><Link to='/about'>About</Link></li>
                <li><Link to='/friends/10'>Friends</Link></li>
                <li><Link to='/detail'>Detail</Link></li>
            </ul>
            <hr />
 
            <Route exact path='/' component={Home} />
            <Route path='/about' component={About} />
            <Route path='/friends/:ids' component={Friends} />
            <Route path='/detail' component={Detail} />
        </div>
    </BrowserRouter>
  );
}
 
const Home = () => (
  <div>
    <h2>Home</h2>
    Homeページです
  </div>
)
const About = () => (
  <div>
    <h2>About</h2>
    Aboutページです
  </div>
)
const Friends = ({ match }) => (
  <div>
    <h2>Friends</h2>
    Friendページです{match.params.ids}
  </div>
)
export default App

追加しているのは、Detailページとそのページへのリンクです。

そして、そのDetailのページがこちら。

import React from 'react';
import { withRouter } from 'react-router';

class Detail extends React.Component {
  handleToAboutPage = () => {
    this.props.history.push('/about')
  }

  render() {
    return (
      <div>
        <button onClick={this.handleToAboutPage}>
          aboutページへ
        </button>
      </div>
    )
  }
}

export default withRouter(Detail)

こちらはAboutページへ遷移するためのボタンが表示されたページです。

上記のコード通り、関数でページ遷移を行うときは、6行目の this.props.history.push([遷移先ページ]) を使います。
ポイントは、最後のexport defaultで指定している Detail を withRouter で囲っている点です。
ページ遷移を実装するときには、こちらの処理が必要になります。
なお、今回別ファイルでDetailページを作成したので、ベースとなるページの3行目にある通り、Detailページを import する作業をお忘れなく。

 

以上、Linkタグを使わずに、関数内でページ遷移を行う方法でした。
ただ、サンプルコードをそのままコピーしただけなので、ベースのページとは少し書き方が違っています。
ベースページでは、const を使っていますが、Detailページでは class を使っているんですよね。
Detailページもベースに合わせたいのですが、書き方が違うのか、const で宣言すると、エラーになってしまい…只今修正中です。
それとも、この書き方でなければいけない何かがあるのかも?
とりあえず、引き続き調査したいと思います。

村上 著者:村上

【React】「react-router」でのページ遷移の実装方法

今回はタイトルにもある通り、CordovaとReactで作成しているアプリにページ遷移を導入する方法についてです。
流石に1ページだけではアプリらしくないですからね。

なお導入方法について、参考にさせていただいた記事はこちら。

react-router@v4を使ってみよう:シンプルなtutorial – Qiita
https://qiita.com/m4iyama/items/b4ca1773580317e7112e

 

さて、導入ですが、まずは下記のコマンドで react-router-dom をインストールします。

npm install react-router-dom

事前準備はこれだけ。
あとは、実際にコードを書いていきます。

import React from 'react'
import { BrowserRouter, Route, Link } from 'react-router-dom'

const App = () => {
  return (
      <BrowserRouter>
        <div>
            <ul>
                <li><Link to='/'>Home</Link></li>
                <li><Link to='/about'>About</Link></li>
                <li><Link to='/friends/10'>Friends</Link></li>
            </ul>
            <hr />

            <Route exact path='/' component={Home} />
            <Route path='/about' component={About} />
            <Route path='/friends/:ids' component={Friends} />
        </div>
    </BrowserRouter>
  );
}

const Home = () => (
  <div>
    <h2>Home</h2>
    Homeページです
  </div>
)
const About = () => (
  <div>
    <h2>About</h2>
    Aboutページです
  </div>
)
const Friends = ({ match }) => (
  <div>
    <h2>Friends</h2>
    Friendページです{match.params.ids}
  </div>
)
export default App

ちなみに、上記のファイルを実際に画面に表示しているのはこちらのコードです。

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';  // 上記のコードが書かれたjsファイル

ReactDOM.render(
    <App />,
    document.getElementById('root')
);

ほぼサンプルコードのままですが、動作を理解するにはぴったりです。
まず、 BrowserRouterタグで一番外側を囲い、Routeタグで表示させたいページとそのURLを指定しています。
リンクについては、Linkタグを使います。
こちらは、HTMLのaタグとイメージが近いと思います。

また、ページ遷移をした際、値を渡すことも可能です。
11行目のfriendsページへのリンク先のように、ページ名の後に /[値] と指定します。
また、16行目のように、URLから値を受け取れるようにします。
そして、受け取った値は、34行目からのFriendsページで取得・表示をしています。
今回は、値を表示させているだけですが、値によって表示するデータを変えるなどの処理が行えます。

基本的なことは、以上が分かっていれば問題なく実装できるかと思います。

 

以上、react-routerでページ遷移を実装する方法でした。
次回は、Linkタグを使わずに、関数内でページ遷移する方法についてご紹介できればと思います。

村上 著者:村上

【Android】「error: resource android:attr/fontVariationSettings not found.」の対処法

今回もAndroidをビルドした際のエラーについて。
最初、ログには「AAPT2 error」としか表示されなかったので、全く意味が分からなかったのですが、詳細を表示したところ、「error: resource android:attr/fontVariationSettings not found.」とのエラーだということが分かりました。
こちらのエラー文によると、「android:attr/fontVariationSettings」というリソースが見つからないという事でしたが、そもそもそんな場所を触った記憶もなく…。

 

で、エラー文で検索をかけたところ、こちらの記事が参考になりました。

android studio 3.0.1 で AAPT2 error が出た時の対応 – Qiita
https://qiita.com/kako351/items/7775157358aaf00da6f9

こちらの記事によると、アプリの build.gradle に、下記を追加して再ビルドすれば良いとのことでした。

configurations.all {
    resolutionStrategy {
        force 'com.android.support:support-v4:27.0.2'
    }
}

試したところ、私の環境でも問題なくビルドが成功しました!

他にも、gradle.properties ファイルに、下記を追加するという方法もあるようでしたが、投稿者の環境ではこの方法では解決しなかったとのことです。

android.enableAapt2=false

たしか、私の環境でも、こちらは意味がなかったような記憶があります。

なので、まずは build.gradle への記述をお試しすることをおすすめします。

 

以上、Android Studio のエラー「error: resource android:attr/fontVariationSettings not found.」の対処法でした。
なお、エラーログに具体的なエラー内容を表示させる方法については、こちらの記事を参考にしてください。

【Android Studio】「Compilation failed to complete」エラーの対処法
https://cpoint-lab.co.jp/article/201809/【android-studio】「compilation-failed-to-complete」エラーの対処法/

Android Studioのエラーって、たまに良く分からないものとかがあったりするので、こうして詳細を表示するように設定しておくと、エラーの種類よっては原因が分かったりすることもあります。

村上 著者:村上

【Android】「No toolchains found in the NDK toolchains folder for ABI with prefix: mipsel-linux-android」エラーの対処法

タイトルにある通り、Android Studioで発生したエラーの対処法についてです。
エラー文はこちら。

No toolchains found in the NDK toolchains folder for ABI with prefix: mipsel-linux-android

NDKツールチェーンフォルダに必要なファイルが足りないことが原因のようでした。

 

今回エラー解消で参考にさせていただいた投稿はこちらから。

“No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android”・Issues #15・google/filament・GitHub
https://github.com/google/filament/issues/15

この中に、AndroidのDeveloperサイトから、NDKをダウンロードしてきて、それを適切な場所に置く、という対処法があり、こちらを行いました。

まず、下記から自分の環境に対応したパッケージをダウンロードします。

NDK のダウンロード|Android NDK|Android Developers
https://developer.android.com/ndk/downloads/?hl=zh-en


私の場合は、「Windows 64 ビット」のパッケージをインストールしました。
ただ、サイズが 700MB くらいあるので、少し時間がかかります。
ダウンロードが完了したら展開しておきましょう。

次に、Android SDKのある場所を開きます。
私のWindows環境では、C:\Users\[ユーザー名]\AppData\Local\Android\sdk でした。
そこにある ndk-bundle フォルダの中の、さらに toolchains フォルダを開きます。

そのフォルダ内に、mips64el-linux-android-4.9mipsel-linux-android-4.9 が足りていなかったため、ダウンロード・展開をしたファイルからその2つをコピーします。

あとは、Android Studio に戻って、再ビルド(もしくは Try Again)を実行します。
私の場合は、これでビルドが完了しました。

 

以上、「No toolchains found in the NDK toolchains folder for ABI with prefix: mipsel-linux-android」というエラーの対処法でした。
こういう、ファイルが足りない系のエラーって面倒ですね…。
が、何とか解決できてよかったです。
もし同じ状況に陥った場合は、是非参考にしてみてください。