بسم الله الرحمن الرحيم
مرحباً بكم أصدقائي جميعاً, اليوم في هذه التدوينة إن شاء الله سوف نتعلم كيفية بناء تطبيق محادثة ” تشات ” بإستخدام منصة الفايربيس ” 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
وفي الختام إسئل الله لي ولكم التوفيق, كما ذكرت إنني سوف أخبركم فكرة بسيطة تستفيد من هذا المشروع في تنفيذها. ذكرتها في فيديو المعاينة.
وانتظرونا بكل جديد ومفيد إن شاء الله .. والسلام عليكم 🙂
ما شاء الله ابدعت اخوي عبدالقادر شكرا لك 🙂
اخي بارك الله فيك… لكن المشكلة بعدم القدرة على تسجيل الدخول الى الموقع من الجوال بحساب google او github
ما الحل؟؟؟
حسب توصلنا للحل, كان الموقع محظور في سوريا .. عند استخدام سجيل الدخول من جوجل .. بالتوفيق لك 🙂
اريد في حال وصلت رسالة من شخص يعمل صوت
من خلال تفعيل media player
فعلت صوت الارسال لكن الاستقبال لا اعرف ما الطريقة ؟
الأمر بسيط .. ولكن سوف اعطيك الفكرة .. وهي ابحث عن الدالة التي يتم استدعائها حال وجود رسالة ..
اعتقد الامر تم توضيحه لك ..
ان شاء الله يوجد جزء اخر لهذا الدرس سوف اقوم به في الفترة القادمة .. تطويرات لهذا التطبيق 🙂
اخي ممكن المساعده
جزاك الله خيرا اخي الكريم ، مدونه متميزه لشخص متميز
بالتوفيق وإلي الأمام
امين يا رب جميعاً, شكراً لك على تشجيعك 🙂
السلام عليكم انا استخدم 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)
لو سمحت انا نزلت المشروع تبعك لما اعمل رن لتطبيق بيعطيني الايرور
شو الحل؟
رجاءا لو سمحت الرابط لا يعمل
تم تعديل الرابط .. شكراً لتذكيرك 🙂
السلام عليكم اولا
وثانيا الله يعطيك الف عافيه بس انا مواجه مشكله فيه
والتي هي :
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
ممكن الحل ؟
بارك الله فيك ,الله يوفقك
اخي ليست متوفرة عندي النت دائما اعرف انه يمكنني التعامل مع الفيربيز افلاين لكن لا اعرف كيف ممكن اخي عبد القادر تشرحلي هذه النقطة
ألف شكر لك ؛ تطبيق ممتاز
لكن هل بالإمكان أن أعمل مراسلة خاص وليس على شكل مجموعة أو غرفة
اهلا وسهلا بك .. بالتأكيد أخي تستطيع 🙂
بارك الله فيك
حضرتك موضوع مش بعيد اوي بس بتمني المساعده كنت عاوز اعمل تطبيق بداخلو ملف pdf ومش عارف الطريقه ازاي ممكن تساعدني وانا معايا البرامج كلها 🙂
نشكرك على هذا الشرح الاكثر من الرائع لكن عندي سؤال مهم .. كيف يمكنني تفعيل الاشعارات عندما تصل رسالة جديدة داخل التطبيق .. بحيث تصل المستخدمين انه هنااك رسالة جديدة وصلت للتطبيق
وشكراً
اخي اندرودي
بتيجي can not resolve symbol firebase!
ليش؟