ในการทำแอปพลิเคชันเกี่ยวกับแผนที่ ถ้าจะให้นักพัฒนาเขียนเองทั้งหมดก็คงไม่ใช่เรื่องง่าย แถมเสียเวลาในการพัฒนาไปอีกมาก ดังนั้นวิธียอดนิยมก็คือการใช้ API ของ Map Engine ที่มีอยู่แล้วของทาง Google ที่เปิดให้นักพัฒนาสามารถเรียกใช้งานได้ เพื่อย่นระยะเวลาในการพัฒนาให้ไวขึ้น สะดวกมากขึ้น ซึ่ง API ตัวนี้จะมีชื่อเรียกว่า Google Maps Android API
Google Maps Android API ได้มีการอัพเดทเปลี่ยนแปลงมาเรื่อยๆจนล่าสุดเป็นเวอร์ชัน 2 แล้ว โดยจะรวมอยู่ใน Google Play Services ที่เป็นศูนย์กลางทำงานของ Google Services ทั้งหลายบนแอนดรอยด์ ดังนั้นแอปพลิเคชันจะเรียกใช้งาน Google Maps ได้ เครื่องนั้นๆก็จะต้องมี Google Apps ติดตั้งอยู่
และในบทความนี้จะเป็นวิธีเรียกใช้งาน Google Maps อย่างง่ายบน Android Studio
สิ่งที่จะต้องทำ
เพื่อเรียกใช้งาน Google Maps ผู้ที่หลงเข้ามาอ่านจะต้องทำดังนี้
• นำรหัส SHA1 จาก Keystore ไปขอ API Key สำหรับ Google Maps ที่ Google Developer Console เพื่อกำหนดโปรเจคของแอปพลิเคชัน
• เพิ่ม Dependencies ของ Google Play Services ลงในโปรเจคของแอปพลิเคชัน
• กำหนด Layout XML สำหรับแสดง Google Maps
• เรียกใช้งานด้วยคำสั่งสำหรับ Google Maps เพื่อใช้งานตามต้องการ
โดย API Key นั้นจะสัมพันธ์กับชุดรหัส SHA1 ใน Keystore ที่ผู้ที่หลงเข้ามาอ่านใช้ Build แอปพลิเคชันตัวนั้นๆและสัมพันธ์กับ Package ของแอปพลิเคชันที่เรียกใช้งาน ดังนั้น API Key นี้จะผูกกับแอปพลิเคชันตัวเดียวเท่านั้น ไม่สามารถนำไปใช้กับแอปตัวอื่นได้ (ทำหลายแอปก็ต้องขอทุกตัว)
• ใช้ SHA1 จาก Debug Keystore ในขณะที่กำลังพัฒนาแอปพลิเคชันอยู่ ยังไม่ได้ Public ขึ้น Google Play Store หรือ 3rd Party App Store
• ใช้ SHA1 จาก Signed Keystore เมื่อพัฒนาแอปพลิเคชันเสร็จแล้ว และพร้อมจะ Public ขึ้น Google Play Store หรือ 3rd Party App Store
ตรงนี้โปรดจำให้ขึ้นใจนะครับ เนื่องจากมีนักพัฒนามือใหม่หลายๆคนชอบมาถามเจ้าของบล็อก เพราะไม่รู้ว่า API Key ต้องใช้คนละตัวกันเวลาทดสอบแอปกับตอน Public ขึ้น Google Play Store (ขี้เกียจตอบบ่อยๆ)
OS X หรือ Linux
~/.android/debug.keystore
Windows
C:\Users\<your_user_name>\.android\debug.keystore
ส่วน Signed Keystore ไม่มีกำหนดที่อยู่ตายตัว เพราะมันคือไฟล์ Keystore ที่ผู้ที่หลงเข้ามาอ่านต้องสร้างเพื่อใช้ Export แอปพลิเคชันเป็น APK ดังนั้นสร้างไฟล์ขึ้นมาแล้วเก็บไว้ที่ไหน ก็อยู่ตรงนั้นน่ะแหละ
• keystore_file_path คือที่อยู่ของไฟล์ Keystore ที่ต้องการอ่าน SHA1
• alias_name Alias Name ของ Keystore นั้นๆ
• alias_pass รหัสผ่านสำหรับ Alias Name
• keystore_pass รหัสผ่านสำหรับ Keystore
ถ้าเป็น Debug Keystore ทาง Google ก็ได้กำหนดตายตัวไว้ตั้งแต่แรกแล้ว
• Alias Name คือ androiddebugkey
• Alias Password คือ android
• Keystore Password คือ android
ยกตัวอย่างเช่น เจ้าของบล็อกใช้ OS X และต้องการ SHA1 ของ Debug Keystore ก็จะต้องใช้คำสั่งดังนี้
ผลที่ได้จะเป็นดังนี้
จะเห็นตรงแถว SHA1 มีชุดรหัสแสดงอยู่ 20 ชุดด้วยกัน ให้เอา SHA1 ที่ได้จากตรงนี้นี่แหละไปขอ API Key จาก Google Developer Console
ในกรณีที่ต้องการอ่าน SHA1 จาก Signed Keystore ก็อย่าลืมนะครับว่าผู้ที่หลงเข้ามาอ่านกำหนด Alias Name และรหัสผ่านไว้ว่าอะไร เพราะผู้ที่หลงเข้ามาอ่านเป็นคนกำหนดเองตอนสร้างไฟล์ Keystore
ถ้าพึ่งเคยเข้ามาครั้งแรกจะยังไม่มีโปรเจค (พอดีเจ้าของบล็อกเคยทำมาก่อนแล้ว) ให้กดปุ่ม Create Project เพื่อทำการสร้างโปรเจค
ตั้งชื่อโปรเจคให้เรียบร้อย ชื่ออะไรก็ได้ขอให้จำได้เป็นพอ เสร็จแล้วกดปุ่ม Create
เมื่อสร้างเสร็จแล้วก็จะเข้าสู่หน้า Overview ของโปรเจคทันที ให้กดเลือกที่ APIs & auth > APIs ที่อยู่ฝั่งซ้ายมือของหน้าเว็ป
ที่หน้านี้จะเป็นการเลือก API ของ Google ว่าจะต้องการใช้ Google Services ตัวไหน ให้เลือก Google Maps Android API
กดที่ปุ่ม Enable API เพื่อเปิดใช้งาน Google Maps Android API
เมื่อเปิดใช้งานเรียบร้อยแล้ว ก็พร้อมใช้งานแล้ว แต่ทว่ายังต้องขอ API Key ก่อนนะ
ให้เลือกไปที่ APIs & auth > Credentials แล้วกดที่ปุ่ม Create new Key ที่ Public API access เพื่อขอ API Key
จะมีหน้าต่างเล็กๆแสดงขึ้นมาว่าจะขอ Key สำหรับอะไร ให้กดเลือกที่ปุ่ม Android Key
จะมีหน้าต่างให้ใส่ SHA1 กับ Package Name ของแอปพลิเคชันลงในช่องว่าง
ยกตัวอย่างว่าแอปของเจ้าของบล็อกกำหนด Package Name ไว้ว่า com.akexorcist.awesomeapp เวลากรอกลงไปในช่องว่างจะต้องใส่ SHA1 ตามด้วย Package Name โดยมีเครื่องหมาย ; เป็นตัวคั่น
<sha1_key>;<package_name>
ดังนั้นของเจ้าของบล็อกก็จะใส่ลงไปแปปนี้
และ API Key สามารถใช้ร่วมกันกับหลายๆแอป โดยใส่หลายๆบรรทัดแบบนี้
เมื่อเสร็จแล้วก็กดปุ่ม Create ได้เลย
ให้ดูที่ Public API Access จะมี API Key แสดงอยู่ พร้อมกับบอก Android applications ที่กรอกลงไปเมื่อครูด้วย ให้เอา API Key ไปใช้งานในแอปได้เลย
แต่เจ้าของบล็อกขอสร้างโปรเจคจาก Blank Activity แทนนะ เพื่ออธิบายวิธีการใช้งาน Google Maps ในแอปพลิเคชัน
สมมติว่าสร้างโปรเจคเสร็จเรียบร้อยแล้ว (Package Name ให้ตรงกับที่ขอ API Key ด้วยนะ)
จากนั้นก็เพิ่ม Dependencies เข้าไปดังนี้
คำสั่งข้างบนเป็นการเพิ่ม Google Maps อย่างเดียวเท่านั้น ซึ่งใน Google Play Services จะมี API หลายๆตัวให้ใช้งาน สามารถดูเพิ่มเติมได้ที่ Setting Up Google Play Services
แล้วก็ Sync Gradle ให้เรียบร้อยซะ
หมายเหตุ ตรวจสอบเวอร์ชันของ Dependencies ด้วย เนื่องจาก Google Play Services มีการอัพเดทใหม่อยู่เสมอ และถ้าใช้แค่ Google Maps ก็ใช้เพิ่มแค่ Dependencies ของ Google Maps API เท่านั้น เพราะการเพิ่ม Google Play Services เข้าไปเกินจำเป็นจะทำให้แอพมีขนาดใหญ่โดยไม่จำเป็น และที่สำคัญอาจจะทำให้เจอปัญหา DEX with Over 65K Methods
Meta Data ตัวนี้เป็นการกำหนดให้รู้ว่า Google Play Services ที่ใช้งานอยู่เป็นเวอร์ชันอะไร เพราะถ้าเวอร์ชันของแอปเราใหม่กว่าที่มีอยู่ในเครื่อง ระบบก็จะให้ผู้ใช้อัพเดท Google Apps ในเครื่องแทน
ต่อไปก็กำหนด API Key สำหรับใช้งาน Google Maps โดยจะใส่เป็น Meta Data ใน Tag ของ <application> เช่นเดิม
ตรง your_api_key ให้ใส่ API Key ที่ได้จาก Google Developer Console
ต่อไปเพิ่ม Permission เข้าไปดังนี้
• INTERNET ดาวน์โหลดแผนที่จาก Server
• ACCESS_NETWORK_STATE ตรวจสอบสถานะการเชื่อมต่อของ Cellular Data ก่อนจะดาวน์โหลดแผนที่
• ACCESS_WIFI_STATE ตรวจสอบสถานะการเชื่อมต่อของ WIFi ก่อนจะดาวน์โหลดแผนที่
• WRITE_EXTERNAL_STORAGE เพื่อทำ Cache สำหรับข้อมูลแผนที่
และจะมีเพิ่มอีกสองตัวเมื่อผู้ที่หลงเข้ามาอ่านเรียกใช้งานคำสั่งแสดงตำแหน่งปัจจุบันของผู้ใช้บน Google Maps แต่ถ้าไม่ได้ใช้งานก็ไม่จำเป็นต้องใส่ก็ได้ โดยให้เลือกอย่างใดอย่างหนึ่งก็พอ ขึ้นอยู่กับผู้ที่หลงเข้ามาอ่านว่าต้องการความแม่นยำในการระบุตำแหน่งของผู้ใช้มากน้อยแค่ไหน
• ACCESS_COARSE_LOCATION ใช้ Cellular Data หรือ WiFi เพื่อหาตำแหน่งของผู้ใช้แบบคร่าวๆ ตำแหน่งที่ได้จะไม่มีความแม่นยำมากนัก
• ACCESS_FINE_LOCATION ใช้ GPS เพื่อหาตำแหน่งของผู้ใช้ให้แม่นยำที่สุดเท่าที่ทำได้
เนื่องจาก Google Maps ใช้ OpenGL ES 2.0 ในการแสดงผลแผนที่ ดังนั้นจะต้องเพิ่ม Tag เพื่อใช้งาน OpenGL ES 2.0 ดังนี้
สรุปคำสั่งที่เพิ่มใน AndroidManifest.xml
AndroidManifest.xml
เมื่อพูดถึงเรื่อง Fragment ก็จะมี Fragment อยู่สองแบบด้วยกัน คือ
• android.app.Fragment (> API 11) ขอเรียกว่า Fragment ปกติ
• android.support.v4.app.Fragment (> API 4) ขอเรียกว่า Support Fragment
ในกรณีที่สร้างแอปสำหรับ API 11 ขึ้นไปก็ใช้ Fragment ปกติก็เพียงพอแล้ว แต่ถ้าอยากให้รองรับในเวอร์ชันก่อนหน้าด้วยก็จะต้องใช้ Support Fragment
ซึ่ง Google Maps ก็เช่นกัน เพราะสร้างอยู่บน Fragment อีกที ดังนั้นคลาส Fragment สำหรับ Google Maps ก็จะมีด้วยกันสองแบบ
• com.google.android.gms.maps.MapFragment (> API 11)
• com.google.android.gms.maps.SupportMapFragment (> API 4)
ถ้าใช้กับ API 11 ขึ้นไปก็สามารถเรียกใช้งานผ่านคลาส MapFragment ได้ทันที แต่ถ้าแอปรองรับกับเวอร์ชันเก่าๆด้วยก็จะต้องเรียกใช้งานผ่าน SupportMapFragment แทน
แต่ทว่าเวลาเรียกใช้งาน Google Maps ผ่านโค๊ดนั้นไม่ได้เรียกสั่งงานจาก MapFragment หรือ SupportMapFragment แต่อย่างใด แต่จะมีคลาสที่ชื่อว่า GoogleMap ให้เรียกใช้งานแทน ส่วน MapFragment กับ SupportMapFragment จะมีไว้ตอนที่เพิ่ม Google Maps ลงในแอปพลิเคชันเท่านั้น
กลับมาที่สองวิธีในการเพิ่ม Google Maps ลงในแอปพลิเคชัน จะมีดังนี้
อย่าลืมว่านี่คือ MapFragment เพราะฉะนั้นถ้าจะใช้ SupportMapFragment ก็แก้ไขให้ถูกต้องด้วย
และเวลาเรียกใช้งานในโค๊ดก็จะเรียกใช้งานแบบนี้
ถ้าเป็น SupportMapFragment ก็จะเป็นแบบนี้
ให้สังเกตที่คำสั่ง getMapAync คำสั่งนี้ใช้สำหรับเตรียม Google Maps ให้พร้อมใช้งาน โดยจะทำงานแบบ Asynchronous ที่จะมี Callback ให้ด้วย ซึ่งมีรูปแบบคำสั่งดังนี้
Callback ที่ว่าก็คือ OnMapReadyCallback ที่จะทำงานเมื่อ Google Maps พร้อมใช้งานแล้ว โดยจะส่ง Instance ของ Google Maps มาให้ใช้งานได้เลย ดังนั้นผู้ที่หลงเข้ามาอ่านก็กำหนดค่าให้กับ Google Maps ที่ตรงนี้ได้เลย
แนะนำเพิ่มเติม สำหรับผู้ที่หลงเข้ามาอ่านคนใดที่ต้องการให้มี View อื่นๆอยู่บน Layout หน้านั้นด้วย ก็ให้ย้าย <fragment> ไปไว้อยู่ใน View Group ตัวไหนก็ได้อีกทีหนึ่ง
ถ้าอยากให้มี View ซ้อนอยู่บน Google Maps ก็ใช้เป็น Relative Layout ได้เลย
เจ้าของบล็อกก็ลองสร้าง Frame Layout ขึ้นมาเพื่อใช้แสดง Google Maps โดยตั้งชื่อ ID ว่า fragment_map_container
จากนั้นก็ใช้คำสั่งเพิ่ม MapFragment หรือ SupportMapFragment ลงใน Frame Layout ตัวนี้ซะ
ในการสร้าง Instance ของ MapFragment หรือ SupportMapFragment ขึ้นมา โดยที่ไม่ได้เตรียมไว้ใน Layout XML จะใช้คำสั่ง newInstances ได้เลย จากนั้นก็เอาไปเพิ่มลงใน Frame Layout จะใช้คำสั่ง add หรือ replace ก็แล้วแต่ผู้ที่หลงเข้ามาอ่าน
และการสร้าง Instance ของ Google Maps ก็จะทำแบบเดียวกับวิธีแรกเลย นั่นก็คือใช้คำสั่ง getMapAsync แบบนี้
เพียงเท่านี้ก็สามารถเรียกใช้งาน Google Maps ได้ตามใจชอบแล้ว
ก็ให้ไปเช็ค API Key ดีๆว่าตอนกำหนด SHA1 เป็นของ Keystore ตัวที่ใช้ Build Project หรือป่าว หรือถ้ามั่นใจว่าถูกแล้วจริงๆ ก็ให้ลง Regenerate Key ดูใหม่ก็ได้ โดยเปิดไปที่ Google Developer Console แล้วจะมีปุ่ม Regenerate key เพื่อสร้าง API Key ใหม่
ระบบจะสร้าง API Key ตัวใหม่มาให้ และตัวเก่าจะถูกยกเลิกใน 24 ชั่วโมง
จากนั้นก็รอซัก 2 นาที แล้วค่อยเอาไปกำหนดใหม่ในแอปพลิเคชันของผู้ที่หลงเข้ามาอ่าน แต่ถ้า Google Maps ยังไม่แสดงก็ให้ลองเช็คให้ดีๆนะครับว่ากำหนดค่า SHA1 กับ Package Name ถูกแล้วแน่นะ?
แต่ก็ไม่ต้องกังวลไป เพราะอย่าลืมว่า
• API Key ได้มาจาก SHA1 ของ Keystore ที่ใช้ Export เป็น APK (ไม่ว่าจะ Debug หรือ Signed Keybstore)
• API Key ได้มาจาก Package Name ของแอปพลิเคชัน
ด้วยสองข้อนี้ ต่อให้เอา API Key ไปได้ แต่ถ้าไม่มี Keystore ของผู้ที่หลงเข้ามาอ่าน และ Package Name ของแอปพลิเคชันไม่เหมือนกัน ก็ใช้ไม่ได้อยู่ดี
ดังนั้น Keystore จึงเป็นสิ่งสำคัญครับ รักษาไว้ให้ดี (Google Account ที่ใช้ Login ใน Google Developer Console ด้วย)
• นำรหัส SHA1 จาก Keystore ไปขอ API Key สำหรับ Google Maps ที่ Google Developer Console เพื่อกำหนดโปรเจคของแอปพลิเคชัน
• เพิ่ม Dependencies ของ Google Play Services ลงในโปรเจคของแอปพลิเคชัน
• กำหนด Layout XML สำหรับแสดง Google Maps
• เรียกใช้งานด้วยคำสั่งสำหรับ Google Maps เพื่อใช้งานตามต้องการ
การขอ API Key สำหรับ Google Maps
การขอ API Key นั้นอาจจะมีขั้นตอนยุ่งยากเล็กน้อย แต่ก็ต้องทำ เพราะว่า API Key เป็นสิ่งที่ทาง Google ใช้ระบุว่าแอปของนักพัฒนาคนไหนมีการเรียกใช้งาน Google Maps บ้าง ถึงแม้ว่า Google Maps จะให้ใช้งานฟรีสำหรับฟีเจอร์เบื้องต้น (ฟีเจอร์พิเศษถึงจะต้องเสียเงิน)โดย API Key นั้นจะสัมพันธ์กับชุดรหัส SHA1 ใน Keystore ที่ผู้ที่หลงเข้ามาอ่านใช้ Build แอปพลิเคชันตัวนั้นๆและสัมพันธ์กับ Package ของแอปพลิเคชันที่เรียกใช้งาน ดังนั้น API Key นี้จะผูกกับแอปพลิเคชันตัวเดียวเท่านั้น ไม่สามารถนำไปใช้กับแอปตัวอื่นได้ (ทำหลายแอปก็ต้องขอทุกตัว)
ชุดรหัส SHA1 จาก Keystore
ชุดรหัส SHA1 จาก Keystore ที่ใช้เพื่อขอ API Key นั้นจะมีอยู่สองแบบด้วยกันคือ SHA1 ของ Debug Keystore และ Signed Keystore โดยมีเงื่อนไขอยู่ว่า• ใช้ SHA1 จาก Debug Keystore ในขณะที่กำลังพัฒนาแอปพลิเคชันอยู่ ยังไม่ได้ Public ขึ้น Google Play Store หรือ 3rd Party App Store
• ใช้ SHA1 จาก Signed Keystore เมื่อพัฒนาแอปพลิเคชันเสร็จแล้ว และพร้อมจะ Public ขึ้น Google Play Store หรือ 3rd Party App Store
ตรงนี้โปรดจำให้ขึ้นใจนะครับ เนื่องจากมีนักพัฒนามือใหม่หลายๆคนชอบมาถามเจ้าของบล็อก เพราะไม่รู้ว่า API Key ต้องใช้คนละตัวกันเวลาทดสอบแอปกับตอน Public ขึ้น Google Play Store (ขี้เกียจตอบบ่อยๆ)
แล้ว Debug Keystore กับ Signed Keystore มันอยู่ที่ไหนล่ะ?
สำหรับ Debug Keystore จะอยู่ที่OS X หรือ Linux
~/.android/debug.keystore
Windows
C:\Users\<your_user_name>\.android\debug.keystore
ส่วน Signed Keystore ไม่มีกำหนดที่อยู่ตายตัว เพราะมันคือไฟล์ Keystore ที่ผู้ที่หลงเข้ามาอ่านต้องสร้างเพื่อใช้ Export แอปพลิเคชันเป็น APK ดังนั้นสร้างไฟล์ขึ้นมาแล้วเก็บไว้ที่ไหน ก็อยู่ตรงนั้นน่ะแหละ
การอ่านชุดรหัส SHA1 จาก Keystore
จะต้องทำผ่าน Terminal (OS X หรือ Linux) หรือ Command Prompt (Windows) ดังนี้keytool -list -v -keystore <keystore_file_path> -alias <alias_name> -storepass <alias_pass> -keypass <keystore_pass>
• keystore_file_path คือที่อยู่ของไฟล์ Keystore ที่ต้องการอ่าน SHA1
• alias_name Alias Name ของ Keystore นั้นๆ
• alias_pass รหัสผ่านสำหรับ Alias Name
• keystore_pass รหัสผ่านสำหรับ Keystore
ถ้าเป็น Debug Keystore ทาง Google ก็ได้กำหนดตายตัวไว้ตั้งแต่แรกแล้ว
• Alias Name คือ androiddebugkey
• Alias Password คือ android
• Keystore Password คือ android
ยกตัวอย่างเช่น เจ้าของบล็อกใช้ OS X และต้องการ SHA1 ของ Debug Keystore ก็จะต้องใช้คำสั่งดังนี้
keytool -list -v -keystore ~/.android/ -alias androiddebugkey -storepass android -keypass android
ผลที่ได้จะเป็นดังนี้
จะเห็นตรงแถว SHA1 มีชุดรหัสแสดงอยู่ 20 ชุดด้วยกัน ให้เอา SHA1 ที่ได้จากตรงนี้นี่แหละไปขอ API Key จาก Google Developer Console
ในกรณีที่ต้องการอ่าน SHA1 จาก Signed Keystore ก็อย่าลืมนะครับว่าผู้ที่หลงเข้ามาอ่านกำหนด Alias Name และรหัสผ่านไว้ว่าอะไร เพราะผู้ที่หลงเข้ามาอ่านเป็นคนกำหนดเองตอนสร้างไฟล์ Keystore
ขอ API Key จาก Google Developer Console
เข้าหน้าเว็ป Google Developer Console แล้วทำการ Login ด้วย Google Account ให้เรียบร้อยซะ จากนั้นก็จะเข้าสู่หน้าแรกของเว็ปถ้าพึ่งเคยเข้ามาครั้งแรกจะยังไม่มีโปรเจค (พอดีเจ้าของบล็อกเคยทำมาก่อนแล้ว) ให้กดปุ่ม Create Project เพื่อทำการสร้างโปรเจค
ตั้งชื่อโปรเจคให้เรียบร้อย ชื่ออะไรก็ได้ขอให้จำได้เป็นพอ เสร็จแล้วกดปุ่ม Create
เมื่อสร้างเสร็จแล้วก็จะเข้าสู่หน้า Overview ของโปรเจคทันที ให้กดเลือกที่ APIs & auth > APIs ที่อยู่ฝั่งซ้ายมือของหน้าเว็ป
ที่หน้านี้จะเป็นการเลือก API ของ Google ว่าจะต้องการใช้ Google Services ตัวไหน ให้เลือก Google Maps Android API
กดที่ปุ่ม Enable API เพื่อเปิดใช้งาน Google Maps Android API
เมื่อเปิดใช้งานเรียบร้อยแล้ว ก็พร้อมใช้งานแล้ว แต่ทว่ายังต้องขอ API Key ก่อนนะ
ให้เลือกไปที่ APIs & auth > Credentials แล้วกดที่ปุ่ม Create new Key ที่ Public API access เพื่อขอ API Key
จะมีหน้าต่างเล็กๆแสดงขึ้นมาว่าจะขอ Key สำหรับอะไร ให้กดเลือกที่ปุ่ม Android Key
จะมีหน้าต่างให้ใส่ SHA1 กับ Package Name ของแอปพลิเคชันลงในช่องว่าง
ยกตัวอย่างว่าแอปของเจ้าของบล็อกกำหนด Package Name ไว้ว่า com.akexorcist.awesomeapp เวลากรอกลงไปในช่องว่างจะต้องใส่ SHA1 ตามด้วย Package Name โดยมีเครื่องหมาย ; เป็นตัวคั่น
<sha1_key>;<package_name>
ดังนั้นของเจ้าของบล็อกก็จะใส่ลงไปแปปนี้
และ API Key สามารถใช้ร่วมกันกับหลายๆแอป โดยใส่หลายๆบรรทัดแบบนี้
เมื่อเสร็จแล้วก็กดปุ่ม Create ได้เลย
ให้ดูที่ Public API Access จะมี API Key แสดงอยู่ พร้อมกับบอก Android applications ที่กรอกลงไปเมื่อครูด้วย ให้เอา API Key ไปใช้งานในแอปได้เลย
นำ API Key ไปใช้ในแอปพลิเคชัน
แน่นอนว่าโปรเจคนั้นต้องสร้างก่อนที่จะขอ API Key ล่ะเนอะ ดังนั้นจึงไม่จำเป็นต้องอธิบายขั้นตอนการสร้างโปรเจค แต่ถ้าอยากจะให้ชีวิตสะดวกสบายขึ้น ตอนสร้างโปรเจคก็จะมี Google Maps Activity ให้เลือกอยู่แล้วแต่เจ้าของบล็อกขอสร้างโปรเจคจาก Blank Activity แทนนะ เพื่ออธิบายวิธีการใช้งาน Google Maps ในแอปพลิเคชัน
สมมติว่าสร้างโปรเจคเสร็จเรียบร้อยแล้ว (Package Name ให้ตรงกับที่ขอ API Key ด้วยนะ)
เพิ่ม Dependencies ของ Google Play Services ลงในโปรเจค
ในกรณีที่พึ่งสร้างโปรเจคขึ้นมาจาก Android Studio ก็ให้เปิด build.gradle ของโมดูลที่ชื่อว่า app ขึ้นมาได้เลย แต่ถ้า Import มาจาก Eclipse อีกทีก็ให้ดูว่าโมดูลตัวไหนคือโมดูลหลักของแอพ แล้วจึงเปิด build.gradle ของโมดูลตัวนั้นๆขึ้นมาจากนั้นก็เพิ่ม Dependencies เข้าไปดังนี้
compile 'com.google.android.gms:play-services-maps:7.5.0'
คำสั่งข้างบนเป็นการเพิ่ม Google Maps อย่างเดียวเท่านั้น ซึ่งใน Google Play Services จะมี API หลายๆตัวให้ใช้งาน สามารถดูเพิ่มเติมได้ที่ Setting Up Google Play Services
แล้วก็ Sync Gradle ให้เรียบร้อยซะ
หมายเหตุ ตรวจสอบเวอร์ชันของ Dependencies ด้วย เนื่องจาก Google Play Services มีการอัพเดทใหม่อยู่เสมอ และถ้าใช้แค่ Google Maps ก็ใช้เพิ่มแค่ Dependencies ของ Google Maps API เท่านั้น เพราะการเพิ่ม Google Play Services เข้าไปเกินจำเป็นจะทำให้แอพมีขนาดใหญ่โดยไม่จำเป็น และที่สำคัญอาจจะทำให้เจอปัญหา DEX with Over 65K Methods
กำหนดค่าใน Android Manifest
อย่างแรกสุดคือการกำหนด Meta Data สำหรับเวอร์ชันของ Google Play Services ใน Tag ของ <application> ของ AndroidManifest.xml ดังนี้<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
Meta Data ตัวนี้เป็นการกำหนดให้รู้ว่า Google Play Services ที่ใช้งานอยู่เป็นเวอร์ชันอะไร เพราะถ้าเวอร์ชันของแอปเราใหม่กว่าที่มีอยู่ในเครื่อง ระบบก็จะให้ผู้ใช้อัพเดท Google Apps ในเครื่องแทน
ต่อไปก็กำหนด API Key สำหรับใช้งาน Google Maps โดยจะใส่เป็น Meta Data ใน Tag ของ <application> เช่นเดิม
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="your_api_key"/>
ตรง your_api_key ให้ใส่ API Key ที่ได้จาก Google Developer Console
ต่อไปเพิ่ม Permission เข้าไปดังนี้
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
• INTERNET ดาวน์โหลดแผนที่จาก Server
• ACCESS_NETWORK_STATE ตรวจสอบสถานะการเชื่อมต่อของ Cellular Data ก่อนจะดาวน์โหลดแผนที่
• ACCESS_WIFI_STATE ตรวจสอบสถานะการเชื่อมต่อของ WIFi ก่อนจะดาวน์โหลดแผนที่
• WRITE_EXTERNAL_STORAGE เพื่อทำ Cache สำหรับข้อมูลแผนที่
และจะมีเพิ่มอีกสองตัวเมื่อผู้ที่หลงเข้ามาอ่านเรียกใช้งานคำสั่งแสดงตำแหน่งปัจจุบันของผู้ใช้บน Google Maps แต่ถ้าไม่ได้ใช้งานก็ไม่จำเป็นต้องใส่ก็ได้ โดยให้เลือกอย่างใดอย่างหนึ่งก็พอ ขึ้นอยู่กับผู้ที่หลงเข้ามาอ่านว่าต้องการความแม่นยำในการระบุตำแหน่งของผู้ใช้มากน้อยแค่ไหน
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
• ACCESS_COARSE_LOCATION ใช้ Cellular Data หรือ WiFi เพื่อหาตำแหน่งของผู้ใช้แบบคร่าวๆ ตำแหน่งที่ได้จะไม่มีความแม่นยำมากนัก
• ACCESS_FINE_LOCATION ใช้ GPS เพื่อหาตำแหน่งของผู้ใช้ให้แม่นยำที่สุดเท่าที่ทำได้
เนื่องจาก Google Maps ใช้ OpenGL ES 2.0 ในการแสดงผลแผนที่ ดังนั้นจะต้องเพิ่ม Tag เพื่อใช้งาน OpenGL ES 2.0 ดังนี้
<uses-feature
android:glEsVersion="0x00020000"
android:required="true"/>
สรุปคำสั่งที่เพิ่มใน AndroidManifest.xml
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.akexorcist.awesomeapp" >
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-feature
android:glEsVersion="0x00020000"
android:required="true"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyATpwzatTxul5iuHePBDKbOngxGg2F8Y"/>
</application>
</manifest>
เพิ่ม Google Maps ในแอปพลิเคชัน
การเพิ่ม Google Maps ลงในแอปจะมีด้วยกันสองวิธี ขึ้นอยู่กับความต้องการของผู้ที่หลงเข้ามาอ่าน โดย Google Maps จะแสดงผลอยู่บน Fragment อีกทีหนึ่ง นั่นก็หมายความว่าการแสดงผล Google Maps เป็นการเรียกใช้งาน Fragment สำหรับ Google Maps นั่นเองเมื่อพูดถึงเรื่อง Fragment ก็จะมี Fragment อยู่สองแบบด้วยกัน คือ
• android.app.Fragment (> API 11) ขอเรียกว่า Fragment ปกติ
• android.support.v4.app.Fragment (> API 4) ขอเรียกว่า Support Fragment
ในกรณีที่สร้างแอปสำหรับ API 11 ขึ้นไปก็ใช้ Fragment ปกติก็เพียงพอแล้ว แต่ถ้าอยากให้รองรับในเวอร์ชันก่อนหน้าด้วยก็จะต้องใช้ Support Fragment
ซึ่ง Google Maps ก็เช่นกัน เพราะสร้างอยู่บน Fragment อีกที ดังนั้นคลาส Fragment สำหรับ Google Maps ก็จะมีด้วยกันสองแบบ
• com.google.android.gms.maps.MapFragment (> API 11)
• com.google.android.gms.maps.SupportMapFragment (> API 4)
ถ้าใช้กับ API 11 ขึ้นไปก็สามารถเรียกใช้งานผ่านคลาส MapFragment ได้ทันที แต่ถ้าแอปรองรับกับเวอร์ชันเก่าๆด้วยก็จะต้องเรียกใช้งานผ่าน SupportMapFragment แทน
แต่ทว่าเวลาเรียกใช้งาน Google Maps ผ่านโค๊ดนั้นไม่ได้เรียกสั่งงานจาก MapFragment หรือ SupportMapFragment แต่อย่างใด แต่จะมีคลาสที่ชื่อว่า GoogleMap ให้เรียกใช้งานแทน ส่วน MapFragment กับ SupportMapFragment จะมีไว้ตอนที่เพิ่ม Google Maps ลงในแอปพลิเคชันเท่านั้น
กลับมาที่สองวิธีในการเพิ่ม Google Maps ลงในแอปพลิเคชัน จะมีดังนี้
วิธีที่ 1 เพิ่ม Google Maps ลงไปโดยตรงใน Layout XML
วิธีนี้ค่อนข้างง่าย เพราะเป็นการประกาศลงไปตรงๆใน Layout XML และยุ่งกับ Fragment ในโค๊ดแค่นิดเดียว<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:name="com.google.android.gms.maps.MapFragment"
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
อย่าลืมว่านี่คือ MapFragment เพราะฉะนั้นถ้าจะใช้ SupportMapFragment ก็แก้ไขให้ถูกต้องด้วย
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
และเวลาเรียกใช้งานในโค๊ดก็จะเรียกใช้งานแบบนี้
MapFragment mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
ถ้าเป็น SupportMapFragment ก็จะเป็นแบบนี้
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
ให้สังเกตที่คำสั่ง getMapAync คำสั่งนี้ใช้สำหรับเตรียม Google Maps ให้พร้อมใช้งาน โดยจะทำงานแบบ Asynchronous ที่จะมี Callback ให้ด้วย ซึ่งมีรูปแบบคำสั่งดังนี้
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.OnMapReadyCallback;
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MapFragment mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
@Override
public void onMapReady(GoogleMap googleMap) {
// Do something with Google Map
}
}
Callback ที่ว่าก็คือ OnMapReadyCallback ที่จะทำงานเมื่อ Google Maps พร้อมใช้งานแล้ว โดยจะส่ง Instance ของ Google Maps มาให้ใช้งานได้เลย ดังนั้นผู้ที่หลงเข้ามาอ่านก็กำหนดค่าให้กับ Google Maps ที่ตรงนี้ได้เลย
แนะนำเพิ่มเติม สำหรับผู้ที่หลงเข้ามาอ่านคนใดที่ต้องการให้มี View อื่นๆอยู่บน Layout หน้านั้นด้วย ก็ให้ย้าย <fragment> ไปไว้อยู่ใน View Group ตัวไหนก็ได้อีกทีหนึ่ง
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<fragment
android:id="@+id/map"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
ถ้าอยากให้มี View ซ้อนอยู่บน Google Maps ก็ใช้เป็น Relative Layout ได้เลย
วิธีที่ 2 เพิ่ม Google Maps แบบเดียวกับ Fragment ทั่วไป
วิธีนี้จะเป็นการเรียก MapFragment หรือ SupportMapFragment ขึ้นมาแล้วยัดลงใน View Group ใดๆก็ตามผ่านโค๊ดคำสั่ง ดังนั้นจึงสามารถเพิ่ม Google Maps ลงไปใน View Group ใดๆก็ได้ ซึ่งจะต่างจากวิธีแรกที่ใช้วิธีการประกาศเป็น Fragment ไว้ตั้งแต่แรกใน Layout XMLเจ้าของบล็อกก็ลองสร้าง Frame Layout ขึ้นมาเพื่อใช้แสดง Google Maps โดยตั้งชื่อ ID ว่า fragment_map_container
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<FrameLayout
android:id="@+id/fragment_map_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
จากนั้นก็ใช้คำสั่งเพิ่ม MapFragment หรือ SupportMapFragment ลงใน Frame Layout ตัวนี้ซะ
MapFragment mapFragment = MapFragment.newInstance();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.my_container, mapFragment);
fragmentTransaction.commit();
ในการสร้าง Instance ของ MapFragment หรือ SupportMapFragment ขึ้นมา โดยที่ไม่ได้เตรียมไว้ใน Layout XML จะใช้คำสั่ง newInstances ได้เลย จากนั้นก็เอาไปเพิ่มลงใน Frame Layout จะใช้คำสั่ง add หรือ replace ก็แล้วแต่ผู้ที่หลงเข้ามาอ่าน
และการสร้าง Instance ของ Google Maps ก็จะทำแบบเดียวกับวิธีแรกเลย นั่นก็คือใช้คำสั่ง getMapAsync แบบนี้
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.OnMapReadyCallback;
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MapFragment mapFragment = MapFragment.newInstance();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.fragment_map_container, mapFragment);
fragmentTransaction.commit();
mapFragment.getMapAsync(this);
}
@Override
public void onMapReady(GoogleMap googleMap) {
// Do something with Google Map
}
}
เพียงเท่านี้ก็สามารถเรียกใช้งาน Google Maps ได้ตามใจชอบแล้ว
ปัญหา Google Maps ไม่แสดง
เจ้าของบล็อกเชื่อว่าคงมีผู้ที่หลงเข้ามาอ่านบางท่านที่ทำตามแล้วเจอปัญหา Google Maps ไม่แสดง โดยส่วนใหญ่แล้วจะเป็นปัญหาจาก API Key ที่ไม่ถูกต้อง และถ้าสังเกตดีๆใน LogCat เวลาที่ Google Maps มีปัญหาก็จะมีข้อความแจ้งเตือนใน LogCat ให้เห็นด้วย เช่น การใส่ API Key ไม่ถูกต้องก็จะขึ้น Authorization failure แบบนี้ก็ให้ไปเช็ค API Key ดีๆว่าตอนกำหนด SHA1 เป็นของ Keystore ตัวที่ใช้ Build Project หรือป่าว หรือถ้ามั่นใจว่าถูกแล้วจริงๆ ก็ให้ลง Regenerate Key ดูใหม่ก็ได้ โดยเปิดไปที่ Google Developer Console แล้วจะมีปุ่ม Regenerate key เพื่อสร้าง API Key ใหม่
ระบบจะสร้าง API Key ตัวใหม่มาให้ และตัวเก่าจะถูกยกเลิกใน 24 ชั่วโมง
จากนั้นก็รอซัก 2 นาที แล้วค่อยเอาไปกำหนดใหม่ในแอปพลิเคชันของผู้ที่หลงเข้ามาอ่าน แต่ถ้า Google Maps ยังไม่แสดงก็ให้ลองเช็คให้ดีๆนะครับว่ากำหนดค่า SHA1 กับ Package Name ถูกแล้วแน่นะ?
คนอื่นแอบเอา API Key ไปใช้ได้หรือไม่?
จะเห็นว่าในการใช้ Google Maps นั้นต้องขอ API Key แล้วเอาไปใส่ใน Android Manifest นั่นก็หมายความว่าตัวแอปพลิเคชันนั้นจะถูก Decompile เพื่อล้วงเอา API Key ได้อย่างง่ายแต่ก็ไม่ต้องกังวลไป เพราะอย่าลืมว่า
• API Key ได้มาจาก SHA1 ของ Keystore ที่ใช้ Export เป็น APK (ไม่ว่าจะ Debug หรือ Signed Keybstore)
• API Key ได้มาจาก Package Name ของแอปพลิเคชัน
ด้วยสองข้อนี้ ต่อให้เอา API Key ไปได้ แต่ถ้าไม่มี Keystore ของผู้ที่หลงเข้ามาอ่าน และ Package Name ของแอปพลิเคชันไม่เหมือนกัน ก็ใช้ไม่ได้อยู่ดี
ดังนั้น Keystore จึงเป็นสิ่งสำคัญครับ รักษาไว้ให้ดี (Google Account ที่ใช้ Login ใน Google Developer Console ด้วย)