はじめに
表題通り、GoogleMapAPIで現在地から1km以内のコンビニを取得する。
成果物

ソースコード
lib/main.dart
import 'package:flutter/material.dart';
import 'screens/nearby_places_screen.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: NearbyPlacesScreen(),
);
}
}
lib/screens/nearby_places_screen.dart
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import '../services/location_service.dart';
import '../services/places_service.dart';
import '../models/place.dart';
class NearbyPlacesScreen extends StatefulWidget {
@override
_NearbyPlacesScreenState createState() => _NearbyPlacesScreenState();
}
class _NearbyPlacesScreenState extends State<NearbyPlacesScreen> {
List<Place> _places = [];
bool _loading = true;
String _error = '';
GoogleMapController? _mapController;
Set<Marker> _markers = {};
LatLng _initialPosition = LatLng(35.6895, 139.6917); // 東京の緯度経度をデフォルトに設定
@override
void initState() {
super.initState();
_loadPlaces();
}
Future<void> _loadPlaces() async {
try {
final position = await LocationService.getCurrentLocation();
_initialPosition = LatLng(position.latitude, position.longitude);
final places = await PlacesService.getNearbyPlaces(
position.latitude, position.longitude);
setState(() {
_places = places;
_markers.add(
Marker(
markerId: MarkerId('currentLocation'),
position: _initialPosition,
infoWindow: InfoWindow(title: 'Current Location'),
),
);
for (var place in places) {
_markers.add(
Marker(
markerId: MarkerId(place.name),
position: LatLng(place.lat, place.lng),
infoWindow: InfoWindow(title: place.name),
),
);
}
_loading = false;
});
} catch (e) {
setState(() {
_error = e.toString();
_loading = false;
});
}
}
void _onMapCreated(GoogleMapController controller) {
_mapController = controller;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Nearby Convenience Stores'),
),
body: _loading
? Center(child: CircularProgressIndicator())
: _error.isNotEmpty
? Center(child: Text('Error: $_error'))
: GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition: CameraPosition(
target: _initialPosition,
zoom: 14.0,
),
markers: _markers,
),
);
}
}
lib/services/location_service.dart
import 'package:geolocator/geolocator.dart';
class LocationService {
static Future<Position> getCurrentLocation() async {
bool serviceEnabled;
LocationPermission permission;
// Location services are not enabled don't continue
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
return Future.error('Location services are disabled.');
}
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
return Future.error('Location permissions are denied');
}
}
if (permission == LocationPermission.deniedForever) {
return Future.error(
'Location permissions are permanently denied, we cannot request permissions.');
}
Position position = await Geolocator.getCurrentPosition();
print('Current position: ${position.latitude}, ${position.longitude}');
return position;
}
}
lib/services/places_service.dart
import 'dart:convert';
import 'package:http/http.dart' as http;
import '../models/place.dart';
class PlacesService {
static final String _apiKey = 'XXXXXXXXXXX';
static Future<List<Place>> getNearbyPlaces(double lat, double lng) async {
final String url =
'https://maps.googleapis.com/maps/api/place/nearbysearch/json'
'?location=$lat,$lng'
'&radius=1000'
'&type=convenience_store'
'&key=$_apiKey';
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
final data = json.decode(response.body);
print('API Response: $data'); // APIレスポンスをログ出力
final results = data['results'] as List;
return results.map((result) => Place.fromJson(result)).toList();
} else {
throw Exception('Failed to load nearby places');
}
}
}
lib/models/place.dart
class Place {
final String name;
final double lat;
final double lng;
Place({required this.name, required this.lat, required this.lng});
factory Place.fromJson(Map<String, dynamic> json) {
return Place(
name: json['name'],
lat: json['geometry']['location']['lat'],
lng: json['geometry']['location']['lng'],
);
}
}
Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- 既存の設定項目 -->
<!-- 位置情報の使用許可の説明を追加 -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>現在地を取得して近くのコンビニを検索するために、位置情報の使用を許可してください。</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>現在地を取得して近くのコンビニを検索するために、常時位置情報の使用を許可してください。</string>
<!-- 既存の設定項目 -->
</dict>
</plist>