ย้ายแอพ Parse Android ของคุณไปยัง Firebase

หากคุณเป็นผู้ใช้ Parse ที่กำลังมองหาโซลูชัน Backend as a Service ทางเลือก Firebase อาจเป็นตัวเลือกที่เหมาะสมที่สุดสำหรับแอป Android ของคุณ

คู่มือนี้จะอธิบายวิธีผสานรวมบริการเฉพาะเข้ากับแอปของคุณ สำหรับคำแนะนำการตั้งค่า Firebase ขั้นพื้นฐาน โปรดดูคู่มือ การตั้งค่า Android

Google Analytics

Google Analytics เป็นโซลูชันการวัดแอปฟรีที่ให้ข้อมูลเชิงลึกเกี่ยวกับการใช้งานแอปและการมีส่วนร่วมของผู้ใช้ Analytics ผสานรวมฟีเจอร์ต่างๆ ของ Firebase และมอบการรายงานแบบไม่จำกัดสำหรับเหตุการณ์ที่แตกต่างกันสูงสุด 500 เหตุการณ์ ซึ่งคุณสามารถกำหนดได้โดยใช้ Firebase SDK

ดู เอกสาร Google Analytics เพื่อเรียนรู้เพิ่มเติม

กลยุทธ์การย้ายถิ่นที่แนะนำ

การใช้ผู้ให้บริการวิเคราะห์หลายรายเป็นสถานการณ์ทั่วไปที่สามารถนำไปใช้กับ Google Analytics ได้อย่างง่ายดาย เพียงเพิ่มลงในแอปของคุณเพื่อรับประโยชน์จากเหตุการณ์และพร็อพเพอร์ตี้ผู้ใช้ที่ Analytics รวบรวมโดยอัตโนมัติ เช่น การเปิดครั้งแรก การอัปเดตแอป รุ่นอุปกรณ์ อายุ

สำหรับเหตุการณ์ที่กำหนดเองและคุณสมบัติผู้ใช้ คุณสามารถใช้กลยุทธ์การเขียนซ้ำได้โดยใช้ทั้ง Parse Analytics และ Google Analytics เพื่อบันทึกเหตุการณ์และคุณสมบัติ ซึ่งช่วยให้คุณค่อยๆ เปิดตัวโซลูชันใหม่ได้

การเปรียบเทียบรหัส

แยกวิเคราะห์

// Start collecting data
ParseAnalytics.trackAppOpenedInBackground(getIntent());

Map<String, String> dimensions = new HashMap<String, String>();
// Define ranges to bucket data points into meaningful segments
dimensions.put("priceRange", "1000-1500");
// Did the user filter the query?
dimensions.put("source", "craigslist");
// Do searches happen more often on weekdays or weekends?
dimensions.put("dayType", "weekday");

// Send the dimensions to Parse along with the 'search' event
ParseAnalytics.trackEvent("search", dimensions);

Google Analytics

// Obtain the FirebaseAnalytics instance and start collecting data
mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);

Bundle params = new Bundle();
// Define ranges to bucket data points into meaningful segments
params.putString("priceRange", "1000-1500");
// Did the user filter the query?
params.putString("source", "craigslist");
// Do searches happen more often on weekdays or weekends?
params.putString("dayType", "weekday");

// Send the event
mFirebaseAnalytics.logEvent("search", params);

ฐานข้อมูลเรียลไทม์ Firebase

ฐานข้อมูลเรียลไทม์ Firebase เป็นฐานข้อมูล NoSQL ที่โฮสต์บนคลาวด์ ข้อมูลจะถูกจัดเก็บเป็น JSON และซิงโครไนซ์แบบเรียลไทม์กับไคลเอนต์ที่เชื่อมต่อทุกตัว

ดู เอกสารฐานข้อมูล Firebase Realtime เพื่อเรียนรู้เพิ่มเติม

ความแตกต่างกับข้อมูลแยกวิเคราะห์

วัตถุ

ใน Parse คุณจัดเก็บ ParseObject หรือคลาสย่อยของ Parse ที่มีคู่คีย์-ค่าของข้อมูลที่เข้ากันได้กับ JSON ข้อมูลไม่มีสคีมา ซึ่งหมายความว่าคุณไม่จำเป็นต้องระบุคีย์ที่มีอยู่ในแต่ละ ParseObject

ข้อมูลฐานข้อมูล Firebase Realtime ทั้งหมดจะถูกจัดเก็บเป็นออบเจ็กต์ JSON และไม่มีอะไรเทียบเท่ากับ ParseObject คุณเพียงแค่เขียนลงในค่าแผนผัง JSON ของประเภทที่สอดคล้องกับประเภท JSON ที่มีอยู่ คุณสามารถใช้ออบเจ็กต์ Java เพื่อทำให้การอ่านและการเขียนจากฐานข้อมูลง่ายขึ้น

ต่อไปนี้คือตัวอย่างวิธีที่คุณอาจบันทึกคะแนนสูงสุดสำหรับเกมได้

แยกวิเคราะห์
@ParseClassName("GameScore")
public class GameScore {
        public GameScore() {}
        public GameScore(Long score, String playerName, Boolean cheatMode) {
            setScore(score);
            setPlayerName(playerName);
            setCheatMode(cheatMode);
        }

        public void setScore(Long score) {
            set("score", score);
        }

        public Long getScore() {
            return getLong("score");
        }

        public void setPlayerName(String playerName) {
            set("playerName", playerName);
        }

        public String getPlayerName() {
            return getString("playerName");
        }

        public void setCheatMode(Boolean cheatMode) {
            return set("cheatMode", cheatMode);
        }

        public Boolean getCheatMode() {
            return getBoolean("cheatMode");
        }
}

// Must call Parse.registerSubclass(GameScore.class) in Application.onCreate
GameScore gameScore = new GameScore(1337, "Sean Plott", false);
gameScore.saveInBackground();
ฐานไฟ
// Assuming we defined the GameScore class as:
public class GameScore {
        private Long score;
        private String playerName;
        private Boolean cheatMode;

        public GameScore() {}
        public GameScore(Long score, String playerName, Boolean cheatMode) {
            this.score = score;
            this.playerName = playerName;
            this.cheatMode = cheatMode;
        }

        public Long getScore() {
            return score;
        }

        public String getPlayerName() {
            return playerName;
        }

        public Boolean getCheatMode() {
            return cheatMode;
        }
}

// We would save it to our list of high scores as follows:
DatabaseReference mFirebaseRef = FirebaseDatabase.getInstance().getReference();
GameScore score = new GameScore(1337, "Sean Plott", false);
mFirebaseRef.child("scores").push().setValue(score);
สำหรับรายละเอียดเพิ่มเติม โปรดดูคู่มือ การอ่านและเขียนข้อมูลบน Android

ความสัมพันธ์ระหว่างข้อมูล

ParseObject สามารถมีความสัมพันธ์กับ ParseObject อื่นได้ : วัตถุใด ๆ สามารถใช้วัตถุอื่นเป็นค่าได้

ใน Firebase Realtime Database ความสัมพันธ์จะแสดงได้ดีกว่าโดยใช้โครงสร้างข้อมูลแบบเรียบที่แยกข้อมูลออกเป็นพาธแยกกัน เพื่อให้สามารถดาวน์โหลดได้อย่างมีประสิทธิภาพในการเรียกแยกกัน

ต่อไปนี้เป็นตัวอย่างของวิธีที่คุณอาจจัดโครงสร้างความสัมพันธ์ระหว่างโพสต์ในแอปบล็อกและผู้เขียน

แยกวิเคราะห์
// Create the author
ParseObject myAuthor = new ParseObject("Author");
myAuthor.put("name", "Grace Hopper");
myAuthor.put("birthDate", "December 9, 1906");
myAuthor.put("nickname", "Amazing Grace");

// Create the post
ParseObject myPost = new ParseObject("Post");
myPost.put("title", "Announcing COBOL, a New Programming Language");

// Add a relation between the Post and the Author
myPost.put("parent", myAuthor);

// This will save both myAuthor and myPost
myPost.saveInBackground();
ฐานไฟ
DatabaseReference firebaseRef = FirebaseDatabase.getInstance().getReference();
// Create the author
Map<String, String> myAuthor = new HashMap<String, String>();
myAuthor.put("name", "Grace Hopper");
myAuthor.put("birthDate", "December 9, 1906");
myAuthor.put("nickname", "Amazing Grace");

// Save the author
String myAuthorKey = "ghopper";
firebaseRef.child('authors').child(myAuthorKey).setValue(myAuthor);

// Create the post
Map<String, String> post = new HashMap<String, String>();
post.put("author", myAuthorKey);
post.put("title", "Announcing COBOL, a New Programming Language");
firebaseRef.child('posts').push().setValue(post);

ผลลัพธ์ที่ได้คือโครงร่างข้อมูลต่อไปนี้

{
  // Info about the authors
  "authors": {
    "ghopper": {
      "name": "Grace Hopper",
      "date_of_birth": "December 9, 1906",
      "nickname": "Amazing Grace"
    },
    ...
  },
  // Info about the posts: the "author" fields contains the key for the author
  "posts": {
    "-JRHTHaIs-jNPLXOQivY": {
      "author": "ghopper",
      "title": "Announcing COBOL, a New Programming Language"
    }
    ...
  }
}
สำหรับรายละเอียดเพิ่มเติม โปรดดูคู่มือ โครงสร้างฐานข้อมูลของคุณ

การอ่านข้อมูล

ใน Parse คุณอ่านข้อมูลโดยใช้ ID ของวัตถุ Parse เฉพาะ หรือดำเนินการค้นหาโดยใช้ ParseQuery

ใน Firebase คุณจะดึงข้อมูลโดยการแนบ Listener แบบอะซิงโครนัสเข้ากับการอ้างอิงฐานข้อมูล Listener จะถูกทริกเกอร์หนึ่งครั้งสำหรับสถานะเริ่มต้นของข้อมูล และอีกครั้งเมื่อข้อมูลเปลี่ยนแปลง ดังนั้นคุณไม่จำเป็นต้องเพิ่มโค้ดใดๆ เพื่อพิจารณาว่าข้อมูลมีการเปลี่ยนแปลงหรือไม่

ต่อไปนี้คือตัวอย่างวิธีที่คุณสามารถดึงคะแนนสำหรับผู้เล่นคนใดคนหนึ่ง โดยยึดตามตัวอย่างที่นำเสนอในส่วน "ออบเจ็กต์"

แยกวิเคราะห์
ParseQuery<ParseObject> query = ParseQuery.getQuery("GameScore");
query.whereEqualTo("playerName", "Dan Stemkoski");
query.findInBackground(new FindCallback<ParseObject>() {
    public void done(List<ParseObject> scoreList, ParseException e) {
        if (e == null) {
            for (ParseObject score: scoreList) {
                Log.d("score", "Retrieved: " + Long.toString(score.getLong("score")));
            }
        } else {
            Log.d("score", "Error: " + e.getMessage());
        }
    }
});
ฐานไฟ
DatabaseReference mFirebaseRef = FirebaseDatabase.getInstance().getReference();
Query mQueryRef = mFirebaseRef.child("scores").orderByChild("playerName").equalTo("Dan Stemkoski");

// This type of listener is not one time, and you need to cancel it to stop
// receiving updates.
mQueryRef.addChildEventListener(new ChildEventListener() {
    @Override
    public void onChildAdded(DataSnapshot snapshot, String previousChild) {
        // This will fire for each matching child node.
        GameScore score = snapshot.getValue(GameScore.class);
        Log.d("score", "Retrieved: " + Long.toString(score.getScore());
    }
});
สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับประเภท Listener เหตุการณ์ที่มีอยู่ และวิธีการสั่งซื้อและกรองข้อมูล โปรดดูคู่มือ การอ่านและเขียนข้อมูลบน Android

กลยุทธ์การย้ายถิ่นที่แนะนำ

คิดใหม่ข้อมูลของคุณ

ฐานข้อมูลเรียลไทม์ Firebase ได้รับการปรับให้เหมาะสมเพื่อซิงค์ข้อมูลในหน่วยมิลลิวินาทีกับไคลเอนต์ที่เชื่อมต่อทั้งหมด และโครงสร้างข้อมูลผลลัพธ์จะแตกต่างจากข้อมูลหลักของ Parse ซึ่งหมายความว่าขั้นตอนแรกของการย้ายข้อมูลคือการพิจารณาว่าข้อมูลของคุณต้องการการเปลี่ยนแปลงอะไรบ้าง ซึ่งรวมถึง:

  • วิธีที่วัตถุแยกวิเคราะห์ของคุณควรแมปกับข้อมูล Firebase
  • หากคุณมีความสัมพันธ์ระหว่างพ่อแม่และลูก วิธีแบ่งข้อมูลของคุณตามเส้นทางต่างๆ เพื่อให้สามารถดาวน์โหลดได้อย่างมีประสิทธิภาพในการเรียกแยกกัน

ย้ายข้อมูลของคุณ

หลังจากที่คุณตัดสินใจได้ว่าจะจัดโครงสร้างข้อมูลใน Firebase อย่างไร คุณจะต้องวางแผนวิธีจัดการกับช่วงเวลาที่แอปของคุณจะต้องเขียนลงฐานข้อมูลทั้งสอง ทางเลือกของคุณคือ:

ซิงค์พื้นหลัง

ในสถานการณ์นี้ คุณมีแอปสองเวอร์ชัน: เวอร์ชันเก่าที่ใช้ Parse และเวอร์ชันใหม่ที่ใช้ Firebase การซิงค์ระหว่างฐานข้อมูลทั้งสองได้รับการจัดการโดย Parse Cloud Code (Parse to Firebase) โดยโค้ดของคุณรับฟังการเปลี่ยนแปลงบน Firebase และซิงค์การเปลี่ยนแปลงเหล่านั้นด้วย Parse ก่อนที่คุณจะเริ่มใช้เวอร์ชันใหม่ได้ คุณต้อง:

  • แปลงข้อมูลแยกวิเคราะห์ที่มีอยู่ของคุณให้เป็นโครงสร้าง Firebase ใหม่ และเขียนลงในฐานข้อมูลเรียลไทม์ของ Firebase
  • เขียนฟังก์ชัน Parse Cloud Code ที่ใช้ Firebase REST API เพื่อเขียนไปยังการเปลี่ยนแปลงฐานข้อมูล Firebase Realtime ที่ทำใน Parse Data โดยไคลเอนต์เก่า
  • เขียนและปรับใช้โค้ดที่รับฟังการเปลี่ยนแปลงบน Firebase และซิงค์กับฐานข้อมูล Parse

สถานการณ์นี้ช่วยให้มั่นใจได้ถึงการแยกโค้ดเก่าและใหม่อย่างชัดเจน และทำให้ไคลเอ็นต์เรียบง่าย ความท้าทายของสถานการณ์นี้คือการจัดการชุดข้อมูลขนาดใหญ่ในการส่งออกครั้งแรก และการทำให้แน่ใจว่าการซิงค์แบบสองทิศทางจะไม่สร้างการเรียกซ้ำแบบไม่มีที่สิ้นสุด

เขียนสองครั้ง

ในสถานการณ์นี้ คุณจะเขียนแอปเวอร์ชันใหม่ที่ใช้ทั้ง Firebase และ Parse โดยใช้ Parse Cloud Code เพื่อซิงค์การเปลี่ยนแปลงที่ทำโดยไคลเอนต์เก่าจาก Parse Data ไปยัง Firebase Realtime Database เมื่อมีคนย้ายจากแอปเวอร์ชัน Parse-only มากพอแล้ว คุณสามารถลบโค้ด Parse ออกจากเวอร์ชันการเขียนซ้ำได้

สถานการณ์นี้ไม่จำเป็นต้องมีโค้ดฝั่งเซิร์ฟเวอร์ ข้อเสียคือข้อมูลที่ไม่มีการเข้าถึงจะไม่ถูกย้าย และขนาดแอปของคุณจะเพิ่มขึ้นตามการใช้งาน SDK ทั้งสอง

การรับรองความถูกต้องของ Firebase

การตรวจสอบสิทธิ์ Firebase สามารถตรวจสอบสิทธิ์ผู้ใช้โดยใช้รหัสผ่านและผู้ให้บริการข้อมูลประจำตัวส่วนกลางยอดนิยม เช่น Google, Facebook และ Twitter นอกจากนี้ยังมีไลบรารี UI เพื่อช่วยคุณประหยัดการลงทุนที่สำคัญที่จำเป็นในการนำไปใช้และรักษาประสบการณ์การตรวจสอบสิทธิ์อย่างเต็มรูปแบบสำหรับแอปของคุณในทุกแพลตฟอร์ม

ดู เอกสารการรับรองความถูกต้องของ Firebase เพื่อเรียนรู้เพิ่มเติม

ความแตกต่างกับ Parse Auth

Parse จัดเตรียมคลาสผู้ใช้พิเศษที่เรียกว่า ParseUser ซึ่งจะจัดการฟังก์ชันการทำงานที่จำเป็นสำหรับการจัดการบัญชีผู้ใช้โดยอัตโนมัติ ParseUser เป็นคลาสย่อยของ ParseObject ซึ่งหมายความว่าข้อมูลผู้ใช้มีอยู่ใน Parse Data และสามารถขยายด้วยฟิลด์เพิ่มเติมได้เช่นเดียวกับ ParseObject อื่นๆ

FirebaseUser มีชุดคุณสมบัติพื้นฐานคงที่ ได้แก่ ID เฉพาะ ที่อยู่อีเมลหลัก ชื่อ และ URL รูปภาพ ซึ่งจัดเก็บไว้ในฐานข้อมูลผู้ใช้ของโปรเจ็กต์แยกต่างหาก ผู้ใช้สามารถอัพเดตคุณสมบัติเหล่านั้นได้ คุณไม่สามารถเพิ่มคุณสมบัติอื่นให้กับวัตถุ FirebaseUser ได้โดยตรง คุณสามารถจัดเก็บคุณสมบัติเพิ่มเติมไว้ในฐานข้อมูลเรียลไทม์ Firebase ของคุณได้แทน

ต่อไปนี้เป็นตัวอย่างของวิธีที่คุณอาจลงทะเบียนผู้ใช้และเพิ่มฟิลด์หมายเลขโทรศัพท์เพิ่มเติม

แยกวิเคราะห์
ParseUser user = new ParseUser();
user.setUsername("my name");
user.setPassword("my pass");
user.setEmail("email@example.com");

// other fields can be set just like with ParseObject
user.put("phone", "650-253-0000");

user.signUpInBackground(new SignUpCallback() {
    public void done(ParseException e) {
        if (e == null) {
            // Hooray! Let them use the app now.
        } else {
            // Sign up didn't succeed. Look at the ParseException
            // to figure out what went wrong
        }
    }
});
ฐานไฟ
FirebaseAuth mAuth = FirebaseAuth.getInstance();

mAuth.createUserWithEmailAndPassword("email@example.com", "my pass")
    .continueWithTask(new Continuation<AuthResult, Task<Void>> {
        @Override
        public Task<Void> then(Task<AuthResult> task) {
            if (task.isSuccessful()) {
                FirebaseUser user = task.getResult().getUser();
                DatabaseReference firebaseRef = FirebaseDatabase.getInstance().getReference();
                return firebaseRef.child("users").child(user.getUid()).child("phone").setValue("650-253-0000");
            } else {
                // User creation didn't succeed. Look at the task exception
                // to figure out what went wrong
                Log.w(TAG, "signInWithEmail", task.getException());
            }
        }
    });

กลยุทธ์การย้ายถิ่นที่แนะนำ

ย้ายบัญชี

หากต้องการย้ายบัญชีผู้ใช้จาก Parse ไปยัง Firebase ให้ส่งออกฐานข้อมูลผู้ใช้ของคุณไปยังไฟล์ JSON หรือ CSV จากนั้นนำเข้าไฟล์ไปยังโปรเจ็กต์ Firebase ของคุณโดยใช้คำสั่ง auth:import ของ Firebase CLI

ขั้นแรก ส่งออกฐานข้อมูลผู้ใช้ของคุณจากคอนโซล Parse หรือฐานข้อมูลที่คุณโฮสต์เอง ตัวอย่างเช่น ไฟล์ JSON ที่ส่งออกจากคอนโซล Parse อาจมีลักษณะดังนี้:

{ // Username/password user
  "bcryptPassword": "$2a$10$OBp2hxB7TaYZgKyTiY48luawlTuYAU6BqzxJfpHoJMdZmjaF4HFh6",
  "email": "user@example.com",
  "username": "testuser",
  "objectId": "abcde1234",
  ...
},
{ // Facebook user
  "authData": {
    "facebook": {
      "access_token": "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
      "expiration_date": "2017-01-02T03:04:05.006Z",
      "id": "1000000000"
    }
  },
  "username": "wXyZ987654321StUv",
  "objectId": "fghij5678",
  ...
}

จากนั้นแปลงไฟล์ที่ส่งออกเป็นรูปแบบที่ Firebase CLI ต้องการ ใช้ objectId ของผู้ใช้ Parse ของคุณเป็น localId ของผู้ใช้ Firebase ของคุณ นอกจากนี้ base64 เข้ารหัสค่า bcryptPassword จาก Parse และใช้ในฟิลด์ passwordHash ตัวอย่างเช่น:

{
  "users": [
    {
      "localId": "abcde1234",  // Parse objectId
      "email": "user@example.com",
      "displayName": "testuser",
      "passwordHash": "JDJhJDEwJE9CcDJoeEI3VGFZWmdLeVRpWTQ4bHVhd2xUdVlBVTZCcXp4SmZwSG9KTWRabWphRjRIRmg2",
    },
    {
      "localId": "fghij5678",  // Parse objectId
      "displayName": "wXyZ987654321StUv",
      "providerUserInfo": [
        {
          "providerId": "facebook.com",
          "rawId": "1000000000",  // Facebook ID
        }
      ]
    }
  ]
}

สุดท้าย นำเข้าไฟล์ที่แปลงแล้วด้วย Firebase CLI โดยระบุ bcrypt เป็นอัลกอริธึมแฮช:

firebase auth:import account_file.json --hash-algo=BCRYPT

ย้ายข้อมูลผู้ใช้

หากคุณกำลังจัดเก็บข้อมูลเพิ่มเติมสำหรับผู้ใช้ของคุณ คุณสามารถย้ายข้อมูลดังกล่าวไปยังฐานข้อมูลเรียลไทม์ Firebase ได้โดยใช้กลยุทธ์ที่อธิบายไว้ในส่วน การย้ายข้อมูล หากคุณย้ายบัญชีโดยใช้ขั้นตอนที่อธิบายไว้ในส่วน การย้ายบัญชี บัญชี Firebase ของคุณจะมี ID เดียวกันกับบัญชี Parse ของคุณ ช่วยให้คุณสามารถย้ายและสร้างความสัมพันธ์ใดๆ ที่คีย์โดย ID ผู้ใช้ได้อย่างง่ายดาย

การส่งข้อความบนคลาวด์ของ Firebase

Firebase Cloud Messaging (FCM) เป็นโซลูชันการส่งข้อความข้ามแพลตฟอร์มที่ช่วยให้คุณส่งข้อความและการแจ้งเตือนได้อย่างน่าเชื่อถือโดยไม่มีค่าใช้จ่าย ตัวเขียนการแจ้งเตือนเป็นบริการที่ไม่มีค่าใช้จ่ายซึ่งสร้างบน Firebase Cloud Messaging ซึ่งเปิดใช้งานการแจ้งเตือนผู้ใช้เป้าหมายสำหรับนักพัฒนาแอปมือถือ

ดู เอกสาร Firebase Cloud Messaging เพื่อเรียนรู้เพิ่มเติม

ความแตกต่างกับการแจ้งเตือนแบบแยกวิเคราะห์

แอปพลิเคชัน Parse ทุกตัวที่ติดตั้งบนอุปกรณ์ที่ลงทะเบียนสำหรับการแจ้งเตือนมีออบเจ็กต์ Installation ที่เกี่ยวข้อง ซึ่งคุณเก็บข้อมูลทั้งหมดที่จำเป็นในการกำหนดเป้าหมายการแจ้งเตือน Installation เป็นคลาสย่อยของ ParseUser ซึ่งหมายความว่าคุณสามารถเพิ่มข้อมูลเพิ่มเติมใดๆ ที่คุณต้องการให้กับอินสแตนซ์ Installation ของคุณได้

ตัวเขียนการแจ้งเตือนจะแสดงกลุ่มผู้ใช้ที่กำหนดไว้ล่วงหน้าโดยอิงตามข้อมูล เช่น แอพ เวอร์ชันแอพ และภาษาของอุปกรณ์ คุณสามารถสร้างกลุ่มผู้ใช้ที่ซับซ้อนมากขึ้นได้โดยใช้เหตุการณ์และพร็อพเพอร์ตี้ของ Google Analytics เพื่อสร้างกลุ่มเป้าหมาย ดูคู่มือช่วยเหลือ ผู้ชม เพื่อเรียนรู้เพิ่มเติม ข้อมูลการกำหนดเป้าหมายเหล่านี้จะไม่ปรากฏในฐานข้อมูล Firebase Realtime

กลยุทธ์การย้ายถิ่นที่แนะนำ

การย้ายโทเค็นอุปกรณ์

ในขณะที่เขียน Parse Android SDK ใช้โทเค็นการลงทะเบียน FCM เวอร์ชันเก่า ซึ่งเข้ากันไม่ได้กับฟีเจอร์ที่นำเสนอโดยผู้แต่งการแจ้งเตือน

คุณสามารถรับโทเค็นใหม่ได้โดยเพิ่ม FCM SDK ลงในแอปของคุณ อย่างไรก็ตาม สิ่งนี้อาจทำให้โทเค็นที่ใช้โดย Parse SDK เพื่อรับการแจ้งเตือนไม่ถูกต้อง หากคุณต้องการหลีกเลี่ยงสิ่งนั้น คุณสามารถตั้งค่า Parse SDK ให้ใช้ทั้ง ID ผู้ส่งของ Parse และ ID ผู้ส่งของคุณ ด้วยวิธีนี้คุณจะไม่ทำให้โทเค็นที่ใช้โดย Parse SDK เป็นโมฆะ แต่โปรดทราบว่าวิธีแก้ปัญหานี้จะหยุดทำงานเมื่อ Parse ปิดโครงการ

การย้ายช่องไปยังหัวข้อ FCM

หากคุณใช้ช่องแยกวิเคราะห์เพื่อส่งการแจ้งเตือน คุณสามารถย้ายไปยังหัวข้อ FCM ซึ่งมีรูปแบบผู้เผยแพร่และสมาชิกเดียวกัน ในการจัดการการเปลี่ยนจาก Parse เป็น FCM คุณสามารถเขียนแอปเวอร์ชันใหม่ที่ใช้ Parse SDK เพื่อยกเลิกการสมัครจากช่อง Parse และ FCM SDK เพื่อสมัครรับหัวข้อ FCM ที่เกี่ยวข้อง ในแอปเวอร์ชันนี้ คุณควรปิดการรับการแจ้งเตือนบน Parse SDK โดยลบสิ่งต่อไปนี้ออกจากรายการแอปของคุณ:

<service android:name="com.parse.PushService" />
<receiver android:name="com.parse.ParsePushBroadcastReceiver"
  android:exported="false">
<intent-filter>
<action android:name="com.parse.push.intent.RECEIVE" />
<action android:name="com.parse.push.intent.DELETE" />
<action android:name="com.parse.push.intent.OPEN" />
</intent-filter>
</receiver>
<receiver android:name="com.parse.GcmBroadcastReceiver"
  android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />

<!--
IMPORTANT: Change "com.parse.starter" to match your app's package name.
-->
<category android:name="com.parse.starter" />
</intent-filter>
</receiver>

<!--
IMPORTANT: Change "YOUR_SENDER_ID" to your GCM Sender Id.
-->
<meta-data android:name="com.parse.push.gcm_sender_id"
  android:value="id:YOUR_SENDER_ID" />;

ตัวอย่างเช่น หากผู้ใช้ของคุณสมัครรับหัวข้อ "Giants" คุณจะดำเนินการดังนี้:

ParsePush.unsubscribeInBackground("Giants", new SaveCallback() {
    @Override
    public void done(ParseException e) {
        if (e == null) {
            FirebaseMessaging.getInstance().subscribeToTopic("Giants");
        } else {
            // Something went wrong unsubscribing
        }
    }
});

เมื่อใช้กลยุทธ์นี้ คุณสามารถส่งข้อความไปยังทั้งช่อง Parse และหัวข้อ FCM ที่เกี่ยวข้อง ซึ่งรองรับผู้ใช้ทั้งเวอร์ชันเก่าและเวอร์ชันใหม่ เมื่อมีผู้ใช้ย้ายจากแอปเวอร์ชัน Parse-only มากพอแล้ว คุณสามารถหยุดเวอร์ชันนั้นและเริ่มส่งโดยใช้ FCM เท่านั้น

ดู เอกสารหัวข้อ FCM เพื่อเรียนรู้เพิ่มเติม

การกำหนดค่าระยะไกลของ Firebase

Firebase Remote Config เป็นบริการระบบคลาวด์ที่ช่วยให้คุณเปลี่ยนลักษณะการทำงานและรูปลักษณ์ของแอปได้โดยไม่ต้องให้ผู้ใช้ดาวน์โหลดการอัปเดตแอป เมื่อใช้การกำหนดค่าระยะไกล คุณจะสร้างค่าเริ่มต้นในแอปที่ควบคุมลักษณะการทำงานและรูปลักษณ์ของแอปของคุณ จากนั้น คุณจะใช้คอนโซล Firebase เพื่อลบล้างค่าเริ่มต้นในแอปสำหรับผู้ใช้แอปทั้งหมดหรือกลุ่มฐานผู้ใช้ของคุณได้ในภายหลัง

การกำหนดค่าระยะไกลของ Firebase จะมีประโยชน์มากในระหว่างการย้ายข้อมูลในกรณีที่คุณต้องการทดสอบโซลูชันต่างๆ และสามารถเปลี่ยนไคลเอ็นต์ไปยังผู้ให้บริการรายอื่นแบบไดนามิกได้มากขึ้น ตัวอย่างเช่น หากคุณมีแอปเวอร์ชันที่ใช้ทั้ง Firebase และ Parse สำหรับข้อมูล คุณสามารถใช้กฎเปอร์เซ็นไทล์แบบสุ่มเพื่อพิจารณาว่าไคลเอ็นต์ใดอ่านจาก Firebase และค่อยๆ เพิ่มเปอร์เซ็นต์

หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับการกำหนดค่าระยะไกลของ Firebase โปรดดู บทแนะนำการกำหนดค่าระยะไกล

ความแตกต่างกับการกำหนดค่าแยกวิเคราะห์

ด้วย Parse config คุณสามารถเพิ่มคู่คีย์/ค่าให้กับแอปของคุณบน Parse Config Dashboard จากนั้นดึง ParseConfig บนไคลเอนต์ ทุกอินสแตนซ์ ParseConfig ที่คุณได้รับจะไม่เปลี่ยนรูปเสมอ เมื่อคุณดึง ParseConfig ใหม่จากเครือข่ายในอนาคต ParseConfig จะไม่แก้ไขอินสแตนซ์ ParseConfig ที่มีอยู่ แต่จะสร้างอินสแตนซ์ใหม่แทนและทำให้พร้อมใช้งานผ่าน getCurrentConfig()

ด้วยการกำหนดค่าระยะไกลของ Firebase คุณจะสร้างค่าเริ่มต้นในแอปสำหรับคู่คีย์/ค่าที่คุณสามารถลบล้างจากคอนโซล Firebase ได้ และคุณสามารถใช้กฎและเงื่อนไขเพื่อมอบประสบการณ์ผู้ใช้แอปที่หลากหลายให้กับฐานผู้ใช้กลุ่มต่างๆ ของคุณ การกำหนดค่าระยะไกลของ Firebase ใช้คลาสเดี่ยวที่ทำให้คู่คีย์/ค่าพร้อมใช้งานสำหรับแอปของคุณ ในตอนแรกซิงเกิลตันจะส่งกลับค่าเริ่มต้นที่คุณกำหนดในแอป คุณสามารถดึงค่าชุดใหม่จากเซิร์ฟเวอร์ได้ทุกเวลาที่สะดวกสำหรับแอปของคุณ หลังจากที่ดึงชุดใหม่สำเร็จแล้ว คุณสามารถเลือกเวลาที่จะเปิดใช้งานเพื่อให้แอปสามารถใช้ค่าใหม่ได้

กลยุทธ์การย้ายถิ่นที่แนะนำ

คุณสามารถย้ายไปยัง Firebase Remote Config ได้โดยการคัดลอกคู่คีย์/ค่าของการกำหนดค่า Parse ของคุณไปยังคอนโซล Firebase จากนั้นปรับใช้แอปเวอร์ชันใหม่ที่ใช้ Firebase Remote Config

หากคุณต้องการทดลองใช้ทั้ง Parse Config และ Firebase Remote Config คุณสามารถปรับใช้แอปเวอร์ชันใหม่ที่ใช้ SDK ทั้งสองได้จนกว่าผู้ใช้จะย้ายจากเวอร์ชัน Parse เท่านั้นมากพอ

การเปรียบเทียบรหัส

แยกวิเคราะห์

ParseConfig.getInBackground(new ConfigCallback() {
    @Override
    public void done(ParseConfig config, ParseException e) {
        if (e == null) {
            Log.d("TAG", "Yay! Config was fetched from the server.");
        } else {
            Log.e("TAG", "Failed to fetch. Using Cached Config.");
            config = ParseConfig.getCurrentConfig();
        }

        // Get the message from config or fallback to default value
        String welcomeMessage = config.getString("welcomeMessage", "Welcome!");
    }
});

ฐานไฟ

mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
// Set defaults from an XML resource file stored in res/xml
mFirebaseRemoteConfig.setDefaults(R.xml.remote_config_defaults);

mFirebaseRemoteConfig.fetch()
    .addOnSuccessListener(new OnSuccessListener<Void>() {
        @Override
        public void onSuccess(Void aVoid) {
            Log.d("TAG", "Yay! Config was fetched from the server.");
            // Once the config is successfully fetched it must be activated before newly fetched
            // values are returned.
            mFirebaseRemoteConfig.activateFetched();
        }
    })
    .addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception exception) {
            Log.e("TAG", "Failed to fetch. Using last fetched or default.");
        }
    })

// ...

// When this is called, the value of the latest fetched and activated config is returned;
// if there's none, the default value is returned.
String welcomeMessage = mFirebaseRemoteConfig.getString("welcomeMessage");