برمجة وتطوير تطبيق تشات اندرويد على منصة فايربيس Firebase

بسم الله الرحمن الرحيم

مرحباً بكم أصدقائي جميعاً, اليوم في هذه التدوينة إن شاء الله سوف نتعلم كيفية بناء تطبيق محادثة ” تشات ” بإستخدام منصة الفايربيس ” firebase “

في البداية شاهد هذه المعاينة فيديو لتطبيق درس اليوم :

# فتح حساب في موقع Firebase + إنشاء تطبيق :

والآن نذهب إلى إنشاء السيرفر الخاص بنا على منصة الفايربيس, للتسجيل في المنصة  إضغط هنا.

سوف يقوم بتسجيلك عن طريق حسابك في جوجل Gmail, حديثاً أصبح يوجد تعامل مشترك بينهم.

هذه المنصة جداً رآئعة وتقدم خدمات منوعة لتطوير التطبيقات, وإن شاء الله في دروس قادمة سوف نشرح أهم الخدمات منها.

بعد التسجيل في الموقع, سجل دخولك في الرئيسية سوف تجد ” مربع صغير في الأسفل ” يوجد فيه خيارات ضع إي اسم تريد, سوف يتم انشاء الرابط تلقائي إن كان موجود مسبقاً ضع اسماً مختلفاً.

من ثم اضغط على CREATE NEW APP . بعد الإنشاء سوف يصبح المربع واضح لديك , ويوجد فيه اسم التطبيق وفيه الـ url وهذا ما سوف نحتاجه, قم بنسخ الرابط لتستخدمه في التطبيق.

# عمل مشروع جديد على الاندرويد ستوديو :

لكيفية بناء مشروع اندرويد فارغ, تابع هذا الفيديو : https://www.youtube.com/watch?v=J36–V2vSJc

# ربط منصة فايربيس بمشروعك :

يجب استخدام اصدار الاندرويد ستوديو 1.4 فما فوق, بعد إنشاء المشروع الجديد من خلال نافذة الأندرويد ستوديو إضغط على File ثم Project Structure. سوف تخرج لك نافذة صغيرة من الجانب الأيسر اختر Cloud.

ثم قم بتفعيل Firebase واضغط ok . تلقائي سوف يقوم بتهيئة المنصة لمشروعك.

من يستخدم إصدار اندرويد ستوديو أقل من 1.4 لا مشكلة, يذهب إلى ملف build.gradle و بداخل أوسمة dependencies يضع السطر التالي :

compile 'com.firebase:firebase-client-android:+'

و الآن بنفس الملف ضع البلوك التالي :

packagingOptions {
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/LICENSE-FIREBASE.txt'
    }

هكذا نكون أنتهينا من تهيئة المنصة لمشروعك.

# ملفات اللياوت المستخدمة في المشروع :

  • login.xml

  • activity_main.xml

  • chat_message.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff321419"
    android:orientation="vertical">


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="نموذج تسجيل الدخول"
        android:textSize="25sp"
        android:layout_margin="30dp"
        android:textColor="#ffc3c3c3"
        android:layout_gravity="center_horizontal" />

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginBottom="50dp"
        android:padding="20dp"
        android:background="#ffc3c3c3">

        <LinearLayout
            android:orientation="vertical"
            android:layout_weight="1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">


            <LinearLayout
                android:orientation="horizontal"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <EditText
                    android:layout_width="150dp"
                    android:layout_height="wrap_content"
                    android:inputType="textPersonName"
                    android:ems="10"
                    android:layout_gravity="left"
                    android:gravity="right"
                    android:layout_margin="10dp"
                    android:id="@+id/user" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="اسم المستخدم"
                    android:textSize="15sp"
                    android:layout_margin="5dp"
                    android:layout_gravity="center_vertical"
                    android:gravity="center_vertical|right" />

            </LinearLayout>

        </LinearLayout>

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#ff8cb2fc"
            android:layout_gravity="center_horizontal">

            <Button
                android:id="@+id/login"
                android:layout_width="wrap_content"
                android:layout_height="30dp"
                android:text="تسجيل الدخول"
                android:layout_margin="25dp"
                android:paddingRight="15dp"
                android:paddingLeft="15dp"
                android:onClick="onClick"
                android:background="#ffc3c3c3"
                android:layout_gravity="center_horizontal" />

        </LinearLayout>

        <TextView
            android:id="@+id/text1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text=""
            android:textColor="#f00"
            android:gravity="center" />


    </LinearLayout>
</LinearLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/bgg"
    tools:context=".MainActivity">

    <ListView
        android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/listFooter"
        android:layout_alignParentTop="true"
        android:transcriptMode="alwaysScroll" />

    <LinearLayout
        android:id="@+id/listFooter"
        android:background="#d9f6f6"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/messageInput"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:inputType="textShortMessage"
            android:lines="1"
            android:singleLine="true" />

        <Button
            android:id="@+id/sendButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Send" />
    </LinearLayout>


</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <LinearLayout
        android:id="@+id/linl"
        android:orientation="vertical"
        android:padding="10dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:textColor="#c9c9c9"
            android:layout_gravity="right"
            android:alpha="0.7"
            android:id="@+id/A_Mess"
            android:background="#fff"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <TextView
            android:id="@+id/Mess"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:gravity="center"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>



</LinearLayout>

activity_main.xml // الواجهة الرئيسية للتطبيق وهي عبارة عن قائمة لست فيو تجلب الرسائل + ادت تكست حقل نصي لإضافة رسالة + زر سيند لارسال الرسالة. وتستخدم خلفية بعنوان bgg

لتحميل الصورة المستخدمة  اضغط هنا . الخلفية توضع في مجلد drawable.

login.xml // صفحة تسجيل الدخول وهي الواجهة التي تظهر فقط قبل تسجيل المستخدم دخوله وتحتوي على حقل نصي لوضع اسم المستخدم فيه + زر تسجيل الدخول + نص تكست فيو يخبرك إذا كان هناك خطأ بالإدخال.

chat_message.xml // وهي الصفحة الخاصة بتنسيق العنصر الواحد من القائمة اللست فيو, إي لتنسيق اسم المرسل ونص الرسالة في الواجهة.

# الاكتفتي المستخدمة في المشروع :

  • Application

  • Chat

  • ChatListAdapter

  • FirebaseListAdapter

  • Login

  • MainActivity

import com.firebase.client.Firebase;

/**
 * Created by Abboudi_Aliwi on 10/24/2015.
 */
public class Application extends android.app.Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Firebase.setAndroidContext(this);
    }
}
/**
 * Created by Abboudi_Aliwi on 10/24/2015.
 */
public class Chat {

    private String message;
    private String author;

    @SuppressWarnings("unused")
    private Chat() {
    }

    Chat(String message, String author) {
        this.message = message;
        this.author = author;
    }

    public String getMessage() {
        return message;
    }

    public String getAuthor() {
        return author;
    }
}
import android.app.Activity;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.firebase.client.Query;

/**
 * Created by Abboudi_Aliwi on 10/24/2015.
 */
public class ChatListAdapter extends FirebaseListAdapter<Chat> {

    private String mUsername;
    private int[] colors = new int[] { 0x30FF0000, 0x300000FF };

    public ChatListAdapter(Query ref, Activity activity, int layout, String mUsername) {
        super(ref, Chat.class, layout, activity);
        this.mUsername = mUsername;
    }

    /**
     * Bind an instance of the <code>Chat</code> class to our view. This method is called by <code>FirebaseListAdapter</code>
     * when there is a data change, and we are given an instance of a View that corresponds to the layout that we passed
     * to the constructor, as well as a single <code>Chat</code> instance that represents the current data to bind.
     *
     * @param view A view instance corresponding to the layout we passed to the constructor.
     * @param chat An instance representing the current state of a chat message
     */
    @Override
    protected void populateView(View view, Chat chat) {
        // Map a Chat object to an entry in our listview
        String author = chat.getAuthor();
        TextView authorText = (TextView) view.findViewById(R.id.A_Mess);
        TextView messText = (TextView) view.findViewById(R.id.Mess);
        authorText.setText(author);
        messText.setText(chat.getMessage());
        // If the message was sent by this user, color it differently
        if (author != null && author.equals(mUsername)) {
            authorText.setText("أنت");
            messText.setTextColor(Color.GREEN);
            messText.setTextSize(18);

        } else {
            messText.setTextColor(Color.BLACK);
            messText.setTextSize(22);
        }
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = super.getView(position, convertView, parent);
        int colorPos = position % colors.length;
        view.setBackgroundColor(colors[colorPos]);
        return view;
    }
}
import android.app.Activity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import com.firebase.client.ChildEventListener;
import com.firebase.client.DataSnapshot;
import com.firebase.client.FirebaseError;
import com.firebase.client.Query;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * This class is a generic way of backing an Android ListView with a Firebase location.
 * It handles all of the child events at the given Firebase location. It marshals received data into the given
 * class type. Extend this class and provide an implementation of <code>populateView</code>, which will be given an
 * instance of your list item mLayout and an instance your class that holds your data. Simply populate the view however
 * you like and this class will handle updating the list as the data changes.
 *
 * @param <T> The class type to use as a model for the data contained in the children of the given Firebase location
 */
public abstract class FirebaseListAdapter<T> extends BaseAdapter {

    private Query mRef;
    private Class<T> mModelClass;
    private int mLayout;
    private LayoutInflater mInflater;
    private List<T> mModels;
    private Map<String, T> mModelKeys;
    private ChildEventListener mListener;


    /**
     * @param mRef        The Firebase location to watch for data changes. Can also be a slice of a location, using some
     *                    combination of <code>limit()</code>, <code>startAt()</code>, and <code>endAt()</code>,
     * @param mModelClass Firebase will marshall the data at a location into an instance of a class that you provide
     * @param mLayout     This is the mLayout used to represent a single list item. You will be responsible for populating an
     *                    instance of the corresponding view with the data from an instance of mModelClass.
     * @param activity    The activity containing the ListView
     */
    public FirebaseListAdapter(Query mRef, Class<T> mModelClass, int mLayout, Activity activity) {
        this.mRef = mRef;
        this.mModelClass = mModelClass;
        this.mLayout = mLayout;
        mInflater = activity.getLayoutInflater();
        mModels = new ArrayList<T>();
        mModelKeys = new HashMap<String, T>();
        // Look for all child events. We will then map them to our own internal ArrayList, which backs ListView
        mListener = this.mRef.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {

                T model = dataSnapshot.getValue(FirebaseListAdapter.this.mModelClass);
                mModelKeys.put(dataSnapshot.getKey(), model);

                // Insert into the correct location, based on previousChildName
                if (previousChildName == null) {
                    mModels.add(0, model);
                } else {
                    T previousModel = mModelKeys.get(previousChildName);
                    int previousIndex = mModels.indexOf(previousModel);
                    int nextIndex = previousIndex + 1;
                    if (nextIndex == mModels.size()) {
                        mModels.add(model);
                    } else {
                        mModels.add(nextIndex, model);
                    }
                }

                notifyDataSetChanged();
            }

            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {

                // One of the mModels changed. Replace it in our list and name mapping
                String modelName = dataSnapshot.getKey();
                T oldModel = mModelKeys.get(modelName);
                T newModel = dataSnapshot.getValue(FirebaseListAdapter.this.mModelClass);
                int index = mModels.indexOf(oldModel);

                mModels.set(index, newModel);
                mModelKeys.put(modelName, newModel);

                notifyDataSetChanged();
            }

            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {

                // A model was removed from the list. Remove it from our list and the name mapping
                String modelName = dataSnapshot.getKey();
                T oldModel = mModelKeys.get(modelName);
                mModels.remove(oldModel);
                mModelKeys.remove(modelName);
                notifyDataSetChanged();
            }

            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {

                // A model changed position in the list. Update our list accordingly
                String modelName = dataSnapshot.getKey();
                T oldModel = mModelKeys.get(modelName);
                T newModel = dataSnapshot.getValue(FirebaseListAdapter.this.mModelClass);
                int index = mModels.indexOf(oldModel);
                mModels.remove(index);
                if (previousChildName == null) {
                    mModels.add(0, newModel);
                } else {
                    T previousModel = mModelKeys.get(previousChildName);
                    int previousIndex = mModels.indexOf(previousModel);
                    int nextIndex = previousIndex + 1;
                    if (nextIndex == mModels.size()) {
                        mModels.add(newModel);
                    } else {
                        mModels.add(nextIndex, newModel);
                    }
                }
                notifyDataSetChanged();
            }

            @Override
            public void onCancelled(FirebaseError firebaseError) {
                Log.e("FirebaseListAdapter", "Listen was cancelled, no more updates will occur");
            }

        });
    }

    public void cleanup() {
        // We're being destroyed, let go of our mListener and forget about all of the mModels
        mRef.removeEventListener(mListener);
        mModels.clear();
        mModelKeys.clear();
    }

    @Override
    public int getCount() {
        return mModels.size();
    }

    @Override
    public Object getItem(int i) {
        return mModels.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        if (view == null) {
            view = mInflater.inflate(mLayout, viewGroup, false);
        }

        T model = mModels.get(i);
        // Call out to subclass to marshall this model into the provided view
        populateView(view, model);
        return view;
    }

    /**
     * Each time the data at the given Firebase location changes, this method will be called for each item that needs
     * to be displayed. The arguments correspond to the mLayout and mModelClass given to the constructor of this class.
     * <p/>
     * Your implementation should populate the view using the data contained in the model.
     *
     * @param v     The view to populate
     * @param model The object containing the data used to populate the view
     */
    protected abstract void populateView(View v, T model);
}
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;

/**
 * Created by Abboudi_Aliwi on 10/24/2015.
 */
public class Login extends Activity {
    EditText uName;
    TextView text1;
    String Name;
    SharedPreferences settings;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.login);
        settings = getSharedPreferences("NAME", 0);
        Boolean check = settings.getBoolean("check", false);


        uName = (EditText) findViewById(R.id.user);
        text1 = (TextView) findViewById(R.id.text1);


        if (check) {
            Intent i = new Intent(Login.this,MainActivity.class);
            startActivity(i);
            finish();
        }

    }

    public void onClick(View v) {

        Name = uName.getText().toString();

        if(Name.isEmpty() || Name.trim().length() < 3){
            text1.setText("من فضلك أدخل اسمك على أن لا يقل عن ثلاث أحرف");
        }else {
            settings = getSharedPreferences("NAME", 0);
            SharedPreferences.Editor editor = settings.edit();
            editor.putBoolean("check", true);
            editor.putString("name", Name);
            editor.apply();
            Intent i1 = new Intent(Login.this,MainActivity.class);
            startActivity(i1);
            finish();
        }

    }
}
import android.app.ListActivity;
import android.content.SharedPreferences;
import android.database.DataSetObserver;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.firebase.client.DataSnapshot;
import com.firebase.client.Firebase;
import com.firebase.client.FirebaseError;
import com.firebase.client.ValueEventListener;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;

/**
 * Created by Abboudi_Aliwi on 10/24/2015.
 */
public class MainActivity extends ListActivity {

    // TODO: change this to your own Firebase URL
    private static final String URL = "https://andrody.firebaseio.com/";

    private String mUsername;
    private Firebase mFirebaseRef;
    private ValueEventListener mConnectedListener;
    private ChatListAdapter mChatListAdapter;
    SharedPreferences settings = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);



        settings = getSharedPreferences("NAME", 0);
        mUsername = settings.getString("name", "");

        setTitle("You : " + mUsername);

        
        mFirebaseRef = new Firebase(URL).child("chat");
        
        EditText inputText = (EditText) findViewById(R.id.messageInput);
        inputText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
                if (actionId == EditorInfo.IME_NULL && keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
                    sendMessage();
                }
                return true;
            }
        });

        findViewById(R.id.sendButton).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                sendMessage();
            }
        });

    }

    @Override
    public void onStart() {
        super.onStart();
        
        final ListView listView = getListView();
        
        mChatListAdapter = new ChatListAdapter(mFirebaseRef.limit(50), this, R.layout.chat_message, mUsername);
        listView.setAdapter(mChatListAdapter);

        listView.setDivider(null);
        mChatListAdapter.registerDataSetObserver(new DataSetObserver() {
            @Override
            public void onChanged() {
                super.onChanged();
                listView.setSelection(mChatListAdapter.getCount() - 1);
            }
        });

        
        mConnectedListener = mFirebaseRef.getRoot().child(".info/connected").addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                boolean connected = (Boolean) dataSnapshot.getValue();
                if (connected) {
                    Toast.makeText(MainActivity.this, "متصل", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(MainActivity.this, "غير متصل", Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onCancelled(FirebaseError firebaseError) {
                // No-op
            }
        });
    }

    @Override
    public void onStop() {
        super.onStop();
        mFirebaseRef.getRoot().child(".info/connected").removeEventListener(mConnectedListener);
        mChatListAdapter.cleanup();
    }

    private void sendMessage() {
        EditText inputText = (EditText) findViewById(R.id.messageInput);
        String input = inputText.getText().toString();
        DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        Calendar cal = Calendar.getInstance();
        if (!input.equals("")) {
            Chat chat = new Chat(input +"\n"+ dateFormat.format(cal.getTime()), mUsername);
            mFirebaseRef.push().setValue(chat);
            inputText.setText("");
        }
    }
}

 Application // كلاس بسيط مشتق من Application ليتم تنفيذه قبل أن يبدأ التطبيق وهو مهم في أغلب المنصات ليتم تعريف التطبيق كامل إنه يستخدم هذه المنصة.

Chat // كلاس واضح تقريباً فهو لعملية الربط .. كمثال توضيح نعرف سترنج .. ونخبره انه هذا السترنج هو نفسه الخاص بنص الرسالة في المنصة و الذي يستخدم بداخل المشروع.

ChatListAdapter // المحول الخاص بكل رسالة تأتي من  السيرفر لكل عنصر داخل القائمة, ومنها نتحكم بتنسيق العنصر الواحد بالقائمة في الرئيسية.

FirebaseListAdapter // المحول الأساسي و أما ChatListAdapter. وهو يمكنك أن تعتبره الكلاس الذي يتم التعامل ما بين التطبيق والموقع firebase أنصح عدم التعديل فيه, فهو فيه دوال اساسية مثلاً إذا تم إضافة نص من الموقع او من جهاز اخر يذهب إلى الموقع ثم يتصل به وياتي به وما يفعله وإذا تم حذف رسالة إلخ .. سهل القراءة لكن تعديله لمن هو متقدم بهذا الأمر.

Login // صفحة تسجيل الدخول, ويوجد فيها أمر إذا تم كتابة اسم المستخدم بنجاح يتم الانتقال تلقائياً للواجهة الرئيسية.

MainActivity // الواجهة الرئيسية بعد تسجيل الدخول, وفيها يتم التحقق من الاتصال وربط السيرفر وعملية ادخال النص وارساله وظهور الرسائل الموجودة بالسيرفر.

# ملف الـ AndroidManifest.xml :

لا يوجد فيه تعديلات ملحوظة فقط إضافة اكتفتي Application لـ وسم ابليكيشن > نيم. وكذلك تأكد من وجود صلاحية الدخول للأنترنت وهي تضاف تلقائياً مع تفعيل المكتبة من الاعدادات.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.andrody.test" >

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:name=".Application"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".Login"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".MainActivity" />
    </application>

</manifest>

# ما يجب عليك تعديله :

سابقاً قمت بإنشاء سيرفر خاص بك, الآن لكي تقوم بإستخدامه في داخل MainActivity.java يوجد لديك url = https://andrody.firebaseio.com قم بإستبدال الرابط بالسيرفر الخاص بك.

أما ما تحتاج تعديله لرفع التطبيق على المتجر هو : تغيير اسم التطبيق + معرف التطبيق الباكيج نيم + ايقونة التطبيق +  يفضل تغيير التصميم.

# تعديلات على المشروع :

++ لتحديد عدد أحرف اسم المستخدم : في داخل Login.java في السطر 43 يوجد : Name.trim().length() < 3 هذا الشرط بحيث إذا كان عدد احرف اسم المستخدم أقل من 3 أحرف يتم رفض الدخول.

++ إذا كنت تريد عدم طباعة التاريخ مع كل رسالة : في داخل MainActivity.java في السطر 117 يوجد الدالة sendMessage() الكود التالي :

private void sendMessage() {
        EditText inputText = (EditText) findViewById(R.id.messageInput);
        String input = inputText.getText().toString();
        DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        Calendar cal = Calendar.getInstance();
        if (!input.equals("")) {
            Chat chat = new Chat(input +"\n"+ dateFormat.format(cal.getTime()), mUsername);
            mFirebaseRef.push().setValue(chat);
            inputText.setText("");
        }
    }

قم باستبدالها لتصبح بالشكل التالي :

private void sendMessage() {
        EditText inputText = (EditText) findViewById(R.id.messageInput);
        String input = inputText.getText().toString();
        if (!input.equals("")) {
            Chat chat = new Chat(input, mUsername);
            mFirebaseRef.push().setValue(chat);
            inputText.setText("");
        }
    }

++ تغيير الإلوان :
تغير لون العناصر بالقائمة من ملف ChatListAdapter.java في السطور الأولى يوجد مصفوفة ألوان قم بتغير القيم بداخلها وهي : 0x30FF0000, 0x300000FF
تغير لون الرسالة بنفس الملف ChatListAdapter.java لون النص المرسل منك Color.GREEN غيره إذا أردت, ولون النص المرسل من الآخرين Color.BLACK

++ إي تعديلات أخرى تحتاجها أكتبها لنا في التعليقات وإن شاء الله في أقرب فرصة نقوم بمساعدتك ~

# تحميل المشروع كامل :

لتحميل المشروع كامل مفتوح المصدر للأندرويد ستوديو, اضغط على لا حول ولا قوة إلا بالله . كلمة سر فك الضغط هي :

andrody.com

وفي الختام إسئل الله لي ولكم التوفيق, كما ذكرت إنني سوف أخبركم فكرة بسيطة تستفيد من هذا المشروع في تنفيذها. ذكرتها في فيديو المعاينة.

وانتظرونا بكل جديد ومفيد إن شاء الله .. والسلام عليكم 🙂

About عبدالقادر عليوي

مواليد 1996 , سوري الجنسية, طالب علم, لدي شغوف كبير في تعلم كل ما يتعلق بالانترنت من تطوير وحماية, أحب القراءة كثيراً .. هدفي نشر العلم بشتى أنواعه ومجالاته, متابع من الدرجة الأولى لـ الدكتور ابراهيم الفقي و الشيخ أحمد ديدات - رحمهم الله -.

Check Also

التقنيات التي نستطيع برمجة تطبيقات والعاب الاندرويد بها

هل أنت محتار من أين تريد البدأ في مجال برمجة التطبيقات للهواتف الذكية أو الألعاب عالية الاداء ؟ تعرف في هذا المقال عن اللغات والتقنيات واختر منها ما يناسبك لدخول هذا المجال

تعلم برمجة تطبيق اندرويد لمدونتك البلوجر (1)

هل لديك تدوينة أو موقع إخباري ؟ أو معرض يعرض الكثير من البيانات من وسائط ؟ وبحاجة لعرضها في تطبيق اندرويد ؟ هذه فرصتك من هنا وللمبتدئين تعلم برمجة تطبيق لمدونتك

عرض صورة في التطبيق من فايربيس

بسم الله الرحمن الرحيم اليوم سيكون شرحنا عن كيفية عرض صورة  في التطبيق من قاعدة …

24 comments

  1. ما شاء الله ابدعت اخوي عبدالقادر شكرا لك 🙂

  2. اخي بارك الله فيك… لكن المشكلة بعدم القدرة على تسجيل الدخول الى الموقع من الجوال بحساب google او github
    ما الحل؟؟؟

  3. البديوي

    اريد في حال وصلت رسالة من شخص يعمل صوت
    من خلال تفعيل media player

    فعلت صوت الارسال لكن الاستقبال لا اعرف ما الطريقة ؟

    • الأمر بسيط .. ولكن سوف اعطيك الفكرة .. وهي ابحث عن الدالة التي يتم استدعائها حال وجود رسالة ..

      اعتقد الامر تم توضيحه لك ..

      ان شاء الله يوجد جزء اخر لهذا الدرس سوف اقوم به في الفترة القادمة .. تطويرات لهذا التطبيق 🙂

  4. جزاك الله خيرا اخي الكريم ، مدونه متميزه لشخص متميز
    بالتوفيق وإلي الأمام

  5. السلام عليكم انا استخدم 1.4 خلاص اضغط اوكي وابداء والا لازم اضيف
    packagingOptions {
    exclude ‘META-INF/LICENSE’
    exclude ‘META-INF/NOTICE’
    exclude ‘META-INF/LICENSE-FIREBASE.txt’
    }

    • وعليكم السلام .. اي نعم اخي اجباري تضيفا

      • مسا الخير اخي انا شفت الفيديو بتاع الشات عملت appبس كيف اربطه مع التطبيق ؟؟؟

        • قصي باجس

          java.lang.RuntimeException: Unable to start activity ComponentInfo{com.andrody.test/com.andrody.test.MainActivity}: java.lang.NullPointerException
          at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
          at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
          at android.app.ActivityThread.access$600(ActivityThread.java:130)
          at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
          at android.os.Handler.dispatchMessage(Handler.java:99)
          at android.os.Looper.loop(Looper.java:137)
          at android.app.ActivityThread.main(ActivityThread.java:4745)
          at java.lang.reflect.Method.invokeNative(Native Method)
          at java.lang.reflect.Method.invoke(Method.java:511)
          at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
          at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
          at dalvik.system.NativeStart.main(Native Method)
          Caused by: java.lang.NullPointerException
          at com.firebase.client.utilities.Utilities.parseUrl(Utilities.java:48)
          at com.firebase.client.Firebase.(Firebase.java:155)
          at com.andrody.test.MainActivity.onCreate(MainActivity.java:51)
          at android.app.Activity.performCreate(Activity.java:5008)
          at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
          at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
                      at android.app.ActivityThread.access$600(ActivityThread.java:130)
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
                      at android.os.Handler.dispatchMessage(Handler.java:99)
                      at android.os.Looper.loop(Looper.java:137)
                      at android.app.ActivityThread.main(ActivityThread.java:4745)
                      at java.lang.reflect.Method.invokeNative(Native Method)
                      at java.lang.reflect.Method.invoke(Method.java:511)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
                      at dalvik.system.NativeStart.main(Native Method)

          لو سمحت انا نزلت المشروع تبعك لما اعمل رن لتطبيق بيعطيني الايرور
          شو الحل؟

      • رجاءا لو سمحت الرابط لا يعمل

  6. السلام عليكم اولا
    وثانيا الله يعطيك الف عافيه بس انا مواجه مشكله فيه
    والتي هي :

    Information:Gradle tasks [:app:assembleDebug]
    :app:preBuild UP-TO-DATE
    :app:preDebugBuild UP-TO-DATE
    :app:checkDebugManifest
    :app:preReleaseBuild UP-TO-DATE
    :app:prepareComAndroidSupportAppcompatV72311Library UP-TO-DATE
    :app:prepareComAndroidSupportSupportV42311Library UP-TO-DATE
    :app:prepareDebugDependencies
    :app:compileDebugAidl UP-TO-DATE
    :app:compileDebugRenderscript UP-TO-DATE
    :app:generateDebugBuildConfig UP-TO-DATE
    :app:generateDebugAssets UP-TO-DATE
    :app:mergeDebugAssets UP-TO-DATE
    :app:generateDebugResValues UP-TO-DATE
    :app:generateDebugResources UP-TO-DATE
    :app:mergeDebugResources UP-TO-DATE
    :app:processDebugManifest UP-TO-DATE
    :app:processDebugResources UP-TO-DATE
    :app:generateDebugSources UP-TO-DATE
    :app:compileDebugJavaWithJavac
    Note: C:\Users\nedal\AndroidStudioProjects\Shat\app\src\main\java\org\nedal\shat\MainActivity.java uses or overrides a deprecated API.
    Note: Recompile with -Xlint:deprecation for details.
    :app:compileDebugNdk UP-TO-DATE
    :app:compileDebugSources
    :app:transformClassesWithDexForDebug
    :app:mergeDebugJniLibFolders UP-TO-DATE
    :app:transformNative_libsWithMergeJniLibsForDebug UP-TO-DATE
    :app:processDebugJavaRes UP-TO-DATE
    :app:transformResourcesWithMergeJavaResForDebug FAILED
    Error:Execution failed for task ‘:app:transformResourcesWithMergeJavaResForDebug’.
    > com.android.build.api.transform.TransformException: com.android.builder.packaging.DuplicateFileException: Duplicate files copied in APK META-INF/NOTICE
    File1: C:\Users\nedal\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-databind\2.2.2\3c8f6018eaa72d43b261181e801e6f8676c16ef6\jackson-databind-2.2.2.jar
    File2: C:\Users\nedal\.gradle\caches\modules-2\files-2.1\com.fasterxml.jackson.core\jackson-core\2.2.2\d20be6a5ddd6f8cfd36ebf6dea329873a1c41f1b\jackson-core-2.2.2.jar
    Information:BUILD FAILED
    Information:Total time: 18.606 secs
    Information:1 error
    Information:0 warnings
    Information:See complete output in console

    ممكن الحل ؟

  7. بارك الله فيك ,الله يوفقك

  8. اخي ليست متوفرة عندي النت دائما اعرف انه يمكنني التعامل مع الفيربيز افلاين لكن لا اعرف كيف ممكن اخي عبد القادر تشرحلي هذه النقطة

  9. حميد علي

    ألف شكر لك ؛ تطبيق ممتاز
    لكن هل بالإمكان أن أعمل مراسلة خاص وليس على شكل مجموعة أو غرفة

  10. عبدالعاطي

    بارك الله فيك

  11. حضرتك موضوع مش بعيد اوي بس بتمني المساعده كنت عاوز اعمل تطبيق بداخلو ملف pdf ومش عارف الطريقه ازاي ممكن تساعدني وانا معايا البرامج كلها 🙂

  12. اسماعيل المؤيد

    نشكرك على هذا الشرح الاكثر من الرائع لكن عندي سؤال مهم .. كيف يمكنني تفعيل الاشعارات عندما تصل رسالة جديدة داخل التطبيق .. بحيث تصل المستخدمين انه هنااك رسالة جديدة وصلت للتطبيق
    وشكراً

  13. اخي اندرودي

    بتيجي can not resolve symbol firebase!

    ليش؟

ضع بصمتك بتعليق يعبر عن امتنانك

هذا الموقع يستخدم Akismet للحدّ من التعليقات المزعجة والغير مرغوبة. تعرّف على كيفية معالجة بيانات تعليقك.