ย้ายข้อมูลแอป Android แยกวิเคราะห์ไปยัง Firebase

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

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

Google Analytics

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

ดูข้อมูลเพิ่มเติมที่เอกสาร Google Analytics

กลยุทธ์การย้ายข้อมูลที่แนะนำ

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

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

การเปรียบเทียบโค้ด

แยกวิเคราะห์ 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 Realtime Database

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

ดูข้อมูลเพิ่มเติมที่เอกสาร Firebase Realtime Database

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

วัตถุ

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

ระบบจัดเก็บข้อมูล Firebase Realtime Database ทั้งหมดเป็นออบเจ็กต์ 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();
Firebase
// 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();
Firebase
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"
    }
    ...
  }
}
ดูรายละเอียดเพิ่มเติมได้ที่ จัดโครงสร้างฐานข้อมูล

กำลังอ่านข้อมูล

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

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

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

แยกวิเคราะห์
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());
        }
    }
});
Firebase
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 Realtime Database ได้รับการเพิ่มประสิทธิภาพเพื่อซิงค์ข้อมูลเป็นมิลลิวินาทีในทุกอุปกรณ์ที่เชื่อมต่อแล้ว และโครงสร้างข้อมูลที่ได้จะแตกต่างจากการแยกวิเคราะห์ข้อมูลหลัก ซึ่งหมายความว่า ขั้นตอนแรกในการย้ายข้อมูลคือพิจารณาว่าข้อมูลต้องการการเปลี่ยนแปลงอะไรบ้าง ซึ่งได้แก่

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

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

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

การซิงค์ในเบื้องหลัง

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

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

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

การเขียนแบบคู่

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

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

Firebase Authentication

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

ดูข้อมูลเพิ่มเติมที่เอกสาร Firebase Authentication

ความแตกต่างกับการตรวจสอบสิทธิ์แบบแยกวิเคราะห์

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

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

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

แยกวิเคราะห์
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
        }
    }
});
Firebase
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());
            }
        }
    });

กลยุทธ์การย้ายข้อมูลที่แนะนำ

ย้ายข้อมูลบัญชี

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

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

{ // 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 ของผู้ใช้การแยกวิเคราะห์เป็น localId ของผู้ใช้ Firebase นอกจากนี้ ให้เข้ารหัส base64 bcryptPassword ค่าจากการแยกวิเคราะห์และใช้ใน 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 Realtime Database ได้ โดยใช้กลยุทธ์ที่อธิบายไว้ในส่วนการย้ายข้อมูล หากคุณย้ายข้อมูล บัญชีโดยใช้ขั้นตอนที่อธิบายไว้ในส่วนการย้ายข้อมูลบัญชี บัญชี Firebase มีรหัสเดียวกันกับบัญชีแยกวิเคราะห์ คุณจึงย้ายข้อมูลและทำซ้ำได้อย่างง่ายดาย ความสัมพันธ์ใดๆ ที่อยู่ภายใต้ User-ID

Firebase Cloud Messaging

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

ดูข้อมูลเพิ่มเติมได้ที่เอกสาร Firebase Cloud Messaging

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

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

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

กลยุทธ์การย้ายข้อมูลที่แนะนำ

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

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

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

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

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

<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
        }
    }
});

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

โปรดดู เอกสาร FCM หัวข้อ เพื่อดูข้อมูลเพิ่มเติม

Firebase Remote Config

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

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

ดูข้อมูลเพิ่มเติมเกี่ยวกับ Firebase Remote Config ได้ที่ ข้อมูลเบื้องต้นเกี่ยวกับ Remote Config

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

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

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

กลยุทธ์การย้ายข้อมูลที่แนะนำ

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

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

การเปรียบเทียบโค้ด

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

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!");
    }
});

Firebase

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");