Firebase Authentication | تسجيل الدخول باستخدام حساب Google


مستوى المقال: مبتدئ

  نبدأ أولاً بإنشاء مشروع جديد على Firebase Console ومشروع جديد على Android Studio ونقوم بربطهم (كما فعلنا في درس Firebase Real-time Database) ثم نضيف مكتبة Firebase Auth في مشروع الأندرويد

compile 'com.google.firebase:firebase-auth:10.2.1'

ونضيف مكتبة Google

compile 'com.google.android.gms:play-services-auth:10.2.1'

ونعمل Sync لGradle وبالطبع نُفعل خيار Google من Firebase Console

FBAG-0.thumb.png.18dbb845afcbc77b02a0b94d6d87708e.png

أما الآن فإننا نحتاج لشيئ يُسمى SHA1 Fingerprint لربطه في Firebase مع تطبيقنا,ويمكنك الحصول عليه عبر تطبيق الخطوات في هذا الشرح أو   اذا كنت تستخدم الويندوز يمكنك تحميل هذه الأداة الصغيرة التي صنعتها والتي تسهل عليك الأمر

 بعد تحميل الأداة وفك الضغط عنها سنجد هذه الملفات

extra1.PNG.b31c68e39982333a5d629ba6ed61ef61.PNG

مايهمنا هو الملفات Genreate Debug Key Google و Genreate Release Key Google

الDebug يقوم بتوليد SHA1 اذا كنت ضمن مرحلة التطوير

نقوم بفتح الملف ونرى ان الأداة تطلب keystore password والتي عادةً تكون "android"

وسنرى أنه تم توليد SHA1 

extra2.png.5988811e76bb973e64dd5768d3f1bb6d.png

 

الRelease عندما تقوم بعمل Release للتطبيق(عندما تقوم بتوليد ملف وشهادة بصيغة jks)

نقوم بفتح الملف وسنجد انه سيطلب alias الذي قد قمت بوضعه عندما قمت بعمل Generate Signed APK 

بعد ذلك سيطلب منك مسار ملف key الذي ينتهي بصيغة jks

ثم الباسوورد

بعد ذلك سيتم توليد الSHA1

extra3.png.fdeb16cfe4c67e8987c086cb2f7aeffe.png

 

قم بنسخه ثم توجه الى Firebase Console ثم اختر Project Settings

FBAG-3.png.de63468eb01b1c39a4734ee564169ab0.png

وانزل للأسفل واختر Add Fingerprint ثم الصق SHA1 الذي نسخته واختر Save

 

FBAG-4.png.04fe8c7a08aa078f47cb8193deea2cf6.png

 

بعد ذلك عليك الذهاب لموقع Google Developers Console للحصول على ClientID سنضعه لاحقاً في مشروع الأندرويد (تأكد من أنه نفس اسم المشروع الذي تعمل عليه في Firebase) ستجد في الأسفل Web Client قم بنسخ Client ID بنوع Web Application (سنحتاجه لاحقاً)

FBAG-5.thumb.png.b130f9e103a5ff79d82356f05217cbc7.png

 

أما الآن نعود الى Android Studio الى activity_main.xml ونضيف زر من نوع SignInButton وهو زر عادي ولكن بشكل جميل وعليه شعار Google

 

FBAG-6.png.53fb973efb22e0fe041c95a97b70b96b.png 

 

بعد ذلك في MainActivity.java سنقوم بتعريف بعض المتغيرات

 

FBAG-7.png.f392293d17857964715bc39a518de423.png

 

  • mAuth شرحناها سابقاً
  • GoogleApiClient مهمته إظهار حسابات Google الموجودة في جهاز الأندرويد
  • SigninButton زر تسجيل الدخول في activity_main.xml
  • RC_SIGN_IN وهو متغير من نوع int عادي سنستخدمه لاحقاً قيمته 0 (يمكنك وضع أي قيمة تريدها)

 

ثم داخل onCreate أعطينا قيمة ل mAuth وعرفنا اوبجكت من GoogleSignInOptions,هذه الميثود مهمتها وضع الإعدادات ليعرف GoogleApiClient ماذا نريد منه, حيث أن Google API Client يحتوي على الكثير من APIs منها Drive API و Google Play Games API الخ..

ثم أعطيناه IDToken (الذي نسخناه سابقاً من Google Developers Console) 

وطلبنا إظهار Email (RequestEmail)

FBAG-8.png.50049e723eeb24b8af075dfc8b11ddc9.png

بعد ذلك علينا تعريف GoogleApiClient ونعطيه gso الذي قمنا بتعريفه

 

FBAG-9.png.cf6c022b282a94fc9eb783619ea2e08c.png

أخيراً نربط SignInButton وعند الضغط عليه نستدعي ميثود signIn التي سننشأها الآن


FBAG-10.png.9d541ea4ad151140d88d251885c83ec2.png

 

داخل ميثود SignIn نقوم بتعريف Intent خاص من Auth ونعطيه mGoogleApiClient ,هذا الأكتفتي هو الذي يظهر حسابات Google الموجودة في الجهاز

 

FBAG-11.png.c7079be14e6f21703cbf2a4ad4f4616c.png

ثم نشغل الأكتفتي ولكن بدلاً من startActivity سنستدعي startActivityForResult ونضع signInIntent و RC_SIGN_IN

لماذا وضعنا startActivityForResult؟

 ببساطة لأننا نريد أن نعرف نتيجة تشغيل هذا الأكتفتي ,على سبيل المثال هل تم اختيار حساب Google أم أن المستخدم قد رفض هذا الأمر

ولمعرفة النتيجة نقوم بعمل Override ل onActivityResult ,هذه الميثود تقوم بإعادة النتيجة وليست فقط ل Google Auth

,فعلى سبيل المثال يمكنك عمل startActivityForResult اذا كنت تريد مثلاً من المستخدم اختيار صورة من الجهاز وبالتالي تريد معرفة هل تم اختيار هذه الصورة أم لا

وللتميز بين results نستخدم رقم int ونقوم بعمل if اذا كان request code == RC_SIGN_IN عندها سنقوم بإنشاء GoogleSignInResult ونعطيه data

وإذا كانت result.isSuccess ناجحة أي أنه تم اختيار حساب من قبل المتسخدم عندها سنقوم بإنشاء GoogleSignInAccount ونأخذه من result.

  الى هذه اللحظة لم يتم تسجيل الحساب في Firebase ولذلك سنستدعي ميثود firebaseAuthWithGoogle  ونعطيه account

FBAG-12.png.d36bf004f5bfa4d446ae6d29b70a5665.png

 

أما الآن سنقوم بإنشاء ميثود firebaseAuthWithGoogle وهي تأخذ GoogleSignInAccount ك بارامتر ثم عرفنا AuthCredential وقمنا بإعطاءه الtoken الخاص بالحساب عبر ميثود acct.getIdToekn أخيراً استعملنا mAuth.signInWithCredential وأضفنا CompleteListener لمعرفة نتيجة العملية

FBAG-13.png.c6cb873f9164f0545389224c271e022c.png

 

أما الآن حان وقت التجربة :D نشغل التطبيق ونضغط على زر SignIn سيتم إظهار نافذة تطلب إختيار حساب كما في الصورة

FBAG-14.png.9c7c31dc5ae45f7990d4b021fbe9a500.png

وإذا تمت العملية بنجاح سنجد النتيجة في Logcat

FBAG-15.png.3d7783f83648e78a94b3b4004c5464c4.png

 

سنذهب ل Firebase Console لنرى هل تم التسجيل بنجاح

FBAG-16.png.5b1ec9a057ad0e701bd7a2dd703cbf36.png

بالطبع يمكنك معرفة هل تم تسجيل الدخول من قبل المستخدم أم لا عبر AuthStateListener كما فعلنا في الدرس السابق

 

المشروع على Github

ملاحظة:المشروع على Github للمعاينة فقط ولايمكنك تجربته على Android Studio لعدم وجود google-services.json الخاص بك  

3llomi

0


اراء المستخدمين


لاتوجد تعليقات لعرضها .



انشئ حساب جديد او قم بتسجيل دخولك لتتمكن من اضافه تعليق جديد

يجب ان تكون عضوا لدينا لتتمكن من التعليق

انشئ حساب جديد

سجل حسابك الجديد لدينا في الموقع بمنتهي السهولة .


سجل حساب جديد

تسجيل الدخول

هل تمتلك حساب بالفعل ؟ سجل دخولك من هنا.


سجل دخولك الان

Ads Belongs To 3llomi

  • بسم الله الرحمن الرحيم
     
    في إستمرارنا في الحديث عن أهم وأحدث مكتبات منصة الأندرويد سنتحدث اليوم عن واحدة من أشهر المكاتب المستخدمة مؤخراً في بعض التطبيقات المشهورة ومن ضمنها تطبيق Jodel الشهير. هذه المكتبة هي مكتبة Crouton. لنتعرف معاً على هذه المكتبة وما أهميتها وكيف تعمل.
    مكتبة Crouton هي مكتبة تتيح لك تنبيه المستخدم وإظهار بعض الإشعارات. تشبه في عملها مكتبة Toast الشهيرة ولكنها تختلف عنها بأنها تحل بعض المشكلات المتعلقة بـ Toast. واحدة من أهم مشاكل الـ Toast هي مشكلة out of context وهي بأن Toast تعمل وتظهر بغض النظر عن الـ context أو المضمون. قد تظهر في سياق مختلف تماماً عن المتوقع أي أنه عند الإنتقال لـ Activity أخرى سيستمر إشعار الـ Toast بالظهور كما أنها غير قابلة للتعديل وموحدة الشكل. كل هذه المشاكل من الممكن حلها بمكاتب مختلفة ولكن من أسهل هذه المكاتب هي Crouton. ولكن السؤال .. كيف تعمل ؟
     
    مكتبة Crouton تتيح لك التحكم الكامل بشكل الإشعارات ولونها وخصائصها بما تتناسب مع تطبيقك. تعطيك كبداية 3 أشكال ثابتة إذا أردت الإبقاء على أشكال Crouton دون أي تغيير. هذه الأشكال هي :
    1-      Alert Notification : باللون الأحمر والخط الأبيض ولمدة 3 ثواني تقريباً
    2-      Info Notification : باللون الأزرق والخط الأبيض ولمدة 3 ثواني تقريباً
    3-      Confirm Notification : باللون الأخضر والخط الأبيض ولمدة 3 ثواني تقريباً
    لنبدأ التطبيق ونرى كيفية إظهار هذه الأشكال.
     
    قبل بداية التطبيق وكما جرت العادة سنحتاج إلى إضافة Dependency لملف build.gradle ولكن هذه المرة سنحتاج لتعديل ملفي الـ gradle.
    بالنسبة لملف build.gradle "project" سنضيف 
    mavenCentral() داخل Block الـ repositories الموجود في buildscript
     
    بالنسبة لملف build.gradle "module" سنضيف
    compile 'de.keyboardsurfer.android.widget:crouton:[email protected]' نقوم بعمل Sync من الأعلى حتى تضاف المكتبة ونستطيع بعدها البدء في العمل.
     
    نقوم بإنشاء Layout بسيطة توضح عمل هذه المكتبة. تحتوي هذه الـ Layout على 3 أزرار خاصة بكل style وأيضاً على زر Toast وزر آخر لتوضيح الـ Custom Notification.
    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingTop="50dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/info" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="INFO" /> <Button android:id="@+id/alert" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="Alert" /> <Button android:id="@+id/succ" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="Success" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:id="@+id/toast" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="Toast" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:id="@+id/custom" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="Custom" /> </LinearLayout> </LinearLayout>  
    صورة توضح الشكل النهائي للـ Layout

     
    نذهب الآن للجزء الأهم وهو ملف الـ Java.
    ملاحظة : سنقوم بتطبيق مفاهيم الـ ButterKnife. لمزيد من المعلومات نرجو زيارة الموضوع التالي:
    دليلك لأفضل مكاتب الأندرويد - الجزء الثاني - ButterKnife
     
    أولاً : سنقوم في البداية بتعريف المتغيرات والـ Buttons
    @BindView(R.id.alert) Button alert; @BindView(R.id.info) Button info; @BindView(R.id.succ) Button succ; @BindView(R.id.toast) Button toast; @BindView(R.id.custom) Button custom;  
    ثانياً : سنقوم بعمل Bind للمتغيرات داخل onCreate method
    ButterKnife.bind(this);  
    ثالثاً : سنقوم بإختيار كل زر للقيام بوظيفة معينة. نلاحظ عندما نريد إظهار Crouton أو إشعار لا نحتاج لتعريف أي متغيرات فهي تعمل بنفس طريقة عمل Toast. لإظهار الإشعارات بالأشكال السابقة التي سبق وتحدثنا عنها سنحتاج لتمرير 3 params فقط وهي الـ Context والنص والشكل سواء كان alert – info – confirm  والطريقة تبدو مشابهة تماماً لطريقة الـ Toast.
    @OnClick(R.id.info) void clicked1() { Crouton.showText(this, "INFO 3alamPro", Style.INFO); } @OnClick(R.id.alert) void clicked2() { Crouton.showText(this, "ALERT 3alamPro", Style.ALERT); } @OnClick(R.id.succ) void clicked3() { Crouton.showText(this, "SUCCESS 3alamPro", Style.CONFIRM); } @OnClick(R.id.toast) void clicked4() { Toast.makeText(getApplicationContext(), "3alamPro", Toast.LENGTH_LONG).show(); }  
    رابعاً : نقوم بإختبار التطبيق ونرى الفرق بين Crouton وبين Toast. وكيف أن Toast تستمر بالظهور حتى عند الخروج من التطبيق ولكن Crouton تختفي وهو المطلوب.

     
    ماذا لو أردنا البقاء على هذه الأشكال ولكن نريد تغيير الوقت المحدد مسبقاً. بكل بساطة سنحتاج لعمل Object من كلاس Configuration الموجود مسبقاً داخل مكتبة Crouton.
    Configuration croutonConfiguration;  
    ومن ثم نعرف الـ Object داخل onCreate method ونعطيه الوقت المطلوب ( الوقت المدخل يقاس بالـ milliseconds والثانية الواحدة تساوي 1000 ميلي ثانية ).
    croutonConfiguration = new Configuration.Builder().setDuration(1000).build(); // 1 sec  
    الآن سنقوم بتغيير الوقت لواحدة من الإشعارات المعرفة مسبقاً ولكننا سنحتاج لتمرير باراميتر إضافي وهو getTaskId() سنتكلم عليه فيما بعد ولكن في الوقت الراهن قد لا يهمنا كثيراً. بهذا التعديل سيتغير الوقت ليصبح ثانية واحدة فقط بدلاً من 3 ثواني.
    @OnClick(R.id.info) void clicked1() { Crouton.showText(this, "INFO 3alamPro", Style.INFO,getTaskId(),croutonConfiguration); }  
    نقوم بالتجربة والمقارنة بين INFO وبين ALERT ونستطيع رؤية الفرق في التوقيت.

     
    بعد الإنتهاء من أول قسم سنبدأ في تصميم الـ Notification الخاصة بنا. وطبعاً هذا الأمر متاح بكل سهولة مع Crouton. سنقوم في البداية بتغيير لون الخط ولون خلفية الإشعار فقط. نلاحظ بأننا كنا نمرر باراميتر من نوع Style داخل crouton. الباراميتر Style.INFO عبارة عن ستايل جاهز ولتغييره سنحتاج لعمل Style خاص بنا. لذلك سنحتاج إلى عمل Object من كلاس style وإضافة جميع الخصائص بشكل يدوي.
    Style style;  
    ونقوم بتعريف الـ Object داخل onCreate method.
    style = new Style.Builder() .setBackgroundColorValue(Color.parseColor("#000000")) // black .setGravity(Gravity.CENTER_HORIZONTAL) .setConfiguration(croutonConfiguration) .setHeight(100) .setTextColorValue(Color.parseColor("#ffffff")).build(); // white  
    للشرح بشكل أعمق للخصائص : 
     setBackgroundColorValue(Color.parseColor()) نستخدمها لإختيار لون خلفية الإشعار.
    setGravity نستخدمها لإختيار مكان النص سواء كان في المنتصف أو على اليمين أو على اليسار.
    setConfiguration نستخدمها لإختيار المدة الزمنية لإظهار الإشعار. (يجب إنشاء Object منفصل كالذي تم إنشاؤه في الخطوات السابقة )
    setHeight نحدد من خلالها إرتفاع الإشعار.
    setTextColorValue نحدد من خلالها لون خط النص داخل الإشعار.
    ومن ثم ننهي التعريف بـ .build
     
    نقوم الآن بتعديل واحدة من الإشعارات المعرفة سابقاً وإختيار الـ style الخاص بنا بدلاً من المعرف مسبقاً.
    @OnClick(R.id.alert) void clicked2() { Crouton.showText(this, "ALERT 3alamPro", style); }  
    ونرى النتيجة. تعمل بشكل مثالي.

     
     
    سنقوم الان بعمل إشعار مختلف تماماً يتضمن صور ونص وليس نص فقط. لتطبيق هذا الأمر سنحتاج إلى إنشاء Layout جديدة. سنقوم داخل هذه الـ Layout بتصميم شكل الإشعار. نقوم بإنشاء Layout جديدة ونسميها crouton_custom على سبيل المثال.

     
    نقوم بتصميم Layout بسيطة تتضمن شعار الموقع فقط. نلاحظ بأن إرتفاع الـ Layout يمثل إرتفاع الإشعار نفسه لذلك إختيار الإرتفاع مهم جداً.
    <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent" android:layout_height="50dp" android:background="#000000"> <ImageView android:layout_width="100dp" android:layout_height="30dp" android:layout_centerInParent="true" android:src="@drawable/pro"/> </RelativeLayout> </RelativeLayout>  
    الشكل النهائي للـ Layout.

     
    للاستمرار بذلك يجب علينا تعريف Object جديد من نوع View وعمل Inflate للـ Layout الخاصة بالإشعار. ومن ثم عمل Crouton جديد.
    @OnClick(R.id.custom) void clicked5() { View customView = getLayoutInflater().inflate(R.layout.crouton_custom, null); Crouton.show(this,customView); }  
    والنتيجة ..

     
    إلى هنا نكون قد وصلنا إلى نهاية الشرح الخاص بالمكتبة. وسنقوم في المواضيع القادمة بإستعراض المزيد من المكتبات الخاصة بمنصة الأندرويد بإذن الله.
    مستوى المقال: مبتدئ

    بواسطه Abdulrahman Hasan Agha , في

  • بسم الله الرحمن الرحيم
    السلام عليكم ورحمة الله وبركاته
     
    Hashing
     
    الكثير من الـ algorithms تستخدم في عملية البحث البسيطة عن Record معين أو Data معينة وسط الآلاف وأحيانا مئات الالاف من الملفات المخزنة في الذاكرة.
    العامل المهم في عملية اختيار الطريقة الممتازة تعتمد على الوقت وفعالية الجهاز المستخدم في عملية البحث ومدى كفائته. وواحدة من أفضل الطرق المستخدمة حالياً هي الـ Hashing .
    سنتعرف معاً في هذا المقال على :
    -          تعريف بسيط عن الـ Hashing.
    -          بعض الطرق المستخدمة في التعامل مع الـ Data في حالة التكرار في طريقة الـ Hashing.
    -          طريقة التطبيق في لغة برمجة Java.
     
    تعريف بسيط عن الـ Hashing:
    هي طريقة تستخدم لحفظ الملفات وتخزينها ومن ثم البحث عنها بأسرع طريقة ممكنة. تتميز هذه الطريقة عن غيرها بأنها قادرة على جلب الـ Data بوقت سريع جدا وسط ملفات ومعلومات كبيرة نوعاً ما مقارنة بغيرها من الطرق.
    هذه الطريقة تتميز بحفظ الـ Data في جدول بحيث يتم إعطاء كل معلومة رقم مميز يتم حفظه داخل جدول من البيانات ومن ثم يتم الوصول إليه مباشرة في حال الحاجة إلى البحث عنه. هذه الطريقة تتميز بقلة الوقت اللازم للقيام بهذه العملية بحيث يمكنك مباشرة معرفة ما إذا كان الملف الجاري البحث عنه موجود أو غير موجود دون الحاجة للبحث عنه داخل الذاكرة بأكملها.
    مثال :
    لنفرض بأن لدينا الأرقام التالية : 1-7-4-8-9-5 .
    إذا قمنا بحفظ هذه الأرقام داخل Array بشكل عشوائي مباشر على سبيل المثال فعند البحث عن رقم 9 ستضطر إلى البحث داخل الـ Array بالكامل لمعرفة ما اذا كان الرقم 9 موجود أو لا. تخيل بأن لديك أكثر من الف رقم او أكثر!! يمكنك تخيل الوقت الطويل الذي ستحتاجه للقيام بعملية البحث هذه.
    لكن باستخدام Hashing يمكننا مثلا تخزين هذه الأرقام داخل Array ولكن ليس بشكل عشوائي كما في السابق وإنما بالنسبة لباقي قسمة العدد على حجم الـ Array على سبيل المثال. لنتفرض بأننا انشأنا Array بحجم 9 خلايا، الصف الأول يوضح الـ index والصف الثاني يوضح العدد الموجود داخل هذا الـ index
    8 7 6 5 4 3 2 1 0 index                   value عند تعبئة هذه الـ Array سنستخدم العلاقة التالية : index = number % arrayLength. بمعنى آخر سيتم وضع الرقم داخل الخانة المعبرة عن باقي قسمة العدد على حجم الـ Array.
    فيكون الجدول بعد التعبئة بهذا الشكل
    8 7 6 5 4 3 2 1 0 index 8 7   5 4     1 9 value لاحظ بأن الرقم 9 وضع بخانة رقم 0 لان باقي قسمة 9 على حجم الـ Array سيعطيك صفر.
    الآن بامكانك مباشرة الذهاب حين البحث عن رقم 9 إلى الرقم المستخرج من الدالة index = number % arrayLength وهو صفر لتعرف ما اذا كان الرقم 9 موجود أو لا وبالتالي توفير الكثير من الوقت.
     
    بعض الطرق المستخدمة في التعامل مع الـ Data في حالة التكرار في طريقة الـ Hashing:
    في المثال السابق لم نصادف أي تكرار في قيمة باقي قسمة الارقام على حجم الـ array ولكن كيف من الممكن حل مشكلة تكرار القيم في حال وقوعها ؟
    هناك الكثير من الحلول التي من الممكن استخدامها لحل هذه المشكلة ولكن سيتم ذكر حل واحد في هذا المقال وسيتم الحديث عن باقي الحلول في مقالات قادمة إن شاء الله.
    1 - Separate Chaining : هذه الطريقة تعتمد على بناء ArrayList بشكل خاص أو أي Structure آخر بشكل عام داخل كل خلية في الـ Hash Table الموضح في الأمثلة السابقة.
    لنأخذ هذه الأعداد على سبيل المثال : 12 – 17 – 29 – 6 – 30 – 31 – 4 – 8 ولنقم بتوزيعها علىHash Table  بحجم 4 خلايا.

     
    في هذه الحالة يتم أولا معرفة الـ index المراد البحث داخله ومن ثم البحث داخل الـ ArrayList لمعرفة ما اذا كان الـ record المراد البحث عنه موجود أو غير موجود.
     
    طريقة التطبيق في لغة برمجة Java:
    هناك الكثير من الطرق لتطبيق فكرة الـ Hashing بواسطة الجافا ولكن سنقوم باتباع الطريقة الأسهل والأقل تعقيداً. سنحتاج إلى إنشاء كلاس List :
    List Class  : عبارة عن كلاس سيتم عمل objects منه  ويحتوي على الـ ArrayList المراد تخزين الـ Data فيها بالإضافة إلى Constructor.
    import java.util.ArrayList; public class List { private ArrayList<Integer> list = new ArrayList<Integer>(); //Constructor public List(){ } public ArrayList<Integer> getList(){ return list ; } }  
    نحتاج أيضاً لإنشاء test class للتأكد من صحة الـ HashTable 
    Test Class : في التيست كلاس سنقوم بإنشاء Array من كلاس List. لاحظ بأنه يجب عليك تعريف كل عناصر هذه الـ Array وبدون هذا التعريف سيظهر لك NullPointerException.
    //hash table List [] hashTable4 = new List [4] ; for (int i = 0 ; i<hashTable4.length ; i++) hashTable4[i] = new List();  
    ميثود print لطباعة الجدول 
    public static void print(List [] array){ for (int i = 0 ; i<array.length ; i++) System.out.println("index "+i+" : "+array[i].getList().toString()); }  
    ميثود getHashCode لمعرفة الـ index المناسب 
    public static int getHashCode(int num){ return num%4 ; }  
    نقوم بتخزين الأرقام في array لتسهيل عملية التصنيف والإدخال ومن ثم نقوم بإدخالها في object hashTable4
    //numbers we want to add int [] listOfNumbers = {12,17,29,30,6,31,4,8}; //add Numbers to the hash table for (int i = 0 ; i<listOfNumbers.length ; i++){ int index = getHashCode(listOfNumbers[i]); hashTable4[index].getList().add(listOfNumbers[i]); }  
    المخرج النهائي 

     
    مستوى المقال: متوسط

    بواسطه Abdulrahman Hasan Agha , في

  • من أكثر الأسباب التي تؤدي الى زيادة معدل تقييم تطبيقك في متجر التطبيقات هو عن طريق سؤال المستخدم من داخل التطبيق !
     
    هناك طرق كثيره ومكتبات متنوعه لفعل ذلك ووظيفتها تكمن في سؤال المستخدم ما اذا اعجبهم التطبيق ويريد كتابة مراجعة له ، فيتم تحويلهم الى متجر التطبيقات
     
    ولكن اليوم سوف نتحدث عن API آبل اضافته في تحديث iOS 10.3
    يطلق عليه SKStoreReviewController
     
    الفكرة في هذا الـ API هو سؤال المستخدم من داخل التطبيق بدون الحاجة الى تحويلهم الى متجر التطبيقات !
    لكن العيب الوحيد هو عدم المقدرة على جعلهم يكتبوا مراجعة للتطبيق ، فقط يستطيعوا تقييم التطبيق عن طريق النجوم .
     
    وطبيعة الحال هناك عدة شروط :
     
         يجب الا يستخدم الـ API بداخل ViewDidLoad  أو ViewWillApper او غيرهم بدون وجود Logic ، فانت لا تريد أن يقيم المستخدم التطبيق بمجرد فتحه لأول مره وهو لم يستخدمه بعد !     يجب ان لا يستخدم الـ API بداخل Button او يتطلب أي Action من المستخدم ، قد يسبب ذلك في رفض تطبيقك اذا وضعته بداخل Action !    تذكر بأن كل شيء يتم تلقائيا اعتماداً على النظام ، من حيث ظهور رسالة طلب التقييم من عدمها ! لهذا السبب وجد الشرط السابق    أهم شرط هو رسالة التقييم سوف تظهر فقط 3 مرات في السنه لكل مستخدم .    اثناء فترة التطوير الرسالة سوف تظهر بشكل دائم     عند ارسال تطبيقك كنسخه تجربيه باستخدام TestFlight الرسالة لن تظهر ! ، بمعنى أخرى سوف تظهر فقط عند نشر تطبيقك في متجر التطبيقات .  
    ومن النصائح اذا اردت تقييم إيجابي للتطبيقك ، اطلب ظهور رسالة التقييم اذا فعل المستخدم امراً إيجابياً !
    ولا تقاطع المستخدم عند عمل مهمه معينه !! ، ولكن اسأله بعد الانتهاء من مهمة محددة
     
    لذا من الأمثله :
     اذا التطبيق متجر الكتروني اطلب رسالة التقييم بعد إتمام الشراء. اذا كان التطبيق لعبة ، اطلب رسالة التقييم بعد تحقيق سكور عالي في اللعبة أو بعد انتهاء من مرحلة او عدة مراحل في اللعبة . اسأله بعدد عدد مرات معينه من استخدام التطبيق وليس من أول مره !
    بحيث تسأل المستخدم لتقييم تطبيقك في وقت يكون في مزاج جيد !  
    اذا كيف يتم استخدامه ؟
     
    كما ذكرت سابقا الأمر بيد المطور
     
    بصورة مختصرة :
     
    الذي يتطلبه هو فقط استدعاء
    import StoreKit  
    في داخل الـ ViewController الذي يريد ظهور الرسالة عليه
     
    ومن ثم استخدام السطر التالي ، في أي مكان يرده المطور
    SKStoreReviewController.requestReview()  
    بصورة افضل هو حساب عدد مرات فتح التطبيق وإظهار الرسالة بعد عدد مرات محدده
    من دراسة قراءتها بأن افضل وقت هو بعد 5 مرات ويفضل بعد 10 مرات
    ولكن ليس أقل من ذلك ، بهذا الوقت بعد 5 مرات او 10 مرات تكون متأكد بأن المستخدم يستخدم التطبيق باستمرار .
     
    اذا كيف تحسب وقت استخدام المستخدم للتطبيق ؟
     
    عن طريق الاستفادة من UserDefaults
     
    اذا لا تعلم ماهو UserDefaults
    فهو طريقة لحفظ البيانات بشكل دائم ويستخدم مع البيانات البسيطة
    كحفظ رقم Integer مثلا
    او حفظ حالة الـ Switch اذا مفعل او مغلق الخ
     
     
    وبالتالي الفكرة هيا بوضع عدد محدد كمتغير وفي هذا المثال سوف نضع المدة 4
    لأننا نريد أن تظهر رسالة التقييم بعد خامس مره ، ولأنه العد يبدأ من 0
    فالرقم 4 = خامس مره
    0 , 1 , 2 , 3 , 4
     
    ونضع متغير اخر يحسب عدد مرات فتح التطبيق (ViewController)
    ومن ثم نعمل مقارنه اذا وصلت عدد المرات الى 5 مرات تظهر الرسالة
    اذا لم يوصل نزود قيمة المتغير ونحفظه في UserDefaults
     
     
     
    الكود يصبح بالشكل التالي :

     
    import UIKit import StoreKit class ViewController: UIViewController {     let minimumRunCount = 4     let userDefaultsKey = "minimumRunCountUserDefaultsKey"     override func viewDidLoad() {         super.viewDidLoad()         if ShowStoreReview() {             SKStoreReviewController.requestReview()         }     }        func ShowStoreReview() -> Bool {         let count = UserDefaults.standard.integer(forKey: userDefaultsKey)         if count >= minimumRunCount {             return true         } else {                        UserDefaults.standard.set((count + 1), forKey: userDefaultsKey)         }         return false     } }  
    اذا كما ذكرنا سابقا
     
    في البداية عرفنا الحد الادنى قبل ظهور الرسالة في  minimumRunCount  
    عرفنا الـ Key للـ userDefault
    يمكنك كتابة أي شي تريده
     
    بالنسبة الى UserDefaults.standard.integer
    القيمة سوف تكون 0 بشكل تلقائي عند استخدامه
    وهذا ما نريده
    لذا قيمة count سوف تكون 0  في اول مره
     
    ومن ثم عملنا مقارنة اذا كانت قيمة count اكبر او يساوي قيمة minimumRunCount  
    تظهر ترجع قيمة true وبالتالي تظهر الرسالة
     
    اذا لم تكون تساوي او اكبر من قيمة  minimumRunCount  
     
    نزود واحد على قيمة count ونحفظها في userDefault
     
    لذا في المره الثانية يفتح فيها التطبيق تكون قيمة count بـ 1
    عوضاً عن 0
     
    وهكذا
     
    وعندما توصل لقيمة 4
    تظهر الرسالة
     
    صورة الرسالة :

     

     
    هذه من الأمثلة التي تستطيع الاستفادة منها
    تستطيع تحسينها حسب احتياجك
     
    اريد أن أوضح نقطة اخيره وهيا الـ SKStoreReviewController
    فقط يظهر لمستخدم نظام 10.3 فأعلى
     
    لذا تستطيع إضافة السطر التالي في ViewDidLoad
     

     
            if #available(iOS 10.3, *) {             SKStoreReviewController.requestReview()                     } else {  وهنا ضع الطريقة القديمة لتحويله الى متجر التطبيقات//         }  
    فيصبح الكود  ViewDidLoad النهائي بالشكل التالي :

     
        override func viewDidLoad() {         super.viewDidLoad()         if ShowStoreReview() {             if #available(iOS 10.3, *) {                 SKStoreReviewController.requestReview()                          } else {             }         }     }  
     
    واخيراً اريد أن اذكر بأن هناك مطور جرب استخدام SKStoreReviewController
    في تطبيقه ، وادى ذلك الي حصوله على 200 تقييم في خلال 8 أيام !
     
    لذا ينصح بشده باستخدام SKStoreReviewController في تطبيقاتكم
     
    فهناك عدد كبير من التطبيقات في المتجر لا تملك أي تقييم !
     
    لذلك آبل إضافة هذا الـ API في نظامها
     
     
    مستوى المقال: محترف

    بواسطه باسل العمودي , في

  • السلام عليكم ورحمة الله وبركاته
    الدرس الثامن : بناء جهاز لقياس درجة الحرارة والرطوبة .

     
    نبذة عن الدرس :
    من خلال هذا الدرس سوف نقوم بعمل جهاز قادر على قراءة درجة الحرارة وايضا نسبة الرطوبة وذلك من خلال مستشعر الحرارة والرطوبة , ويتم عرضها على الشاشة الكريستالية , المقاومة المتغيرة لتغيير سطوع الشاشة .
     
    متطلبات المشروع :
    أردوينو اونو (Arduino Uno)
    مستشعر الحرارة والرطوبة (DHT11 or DHT22)
    مقاومة متغيرة (variable resistor)
    الشاشة كريستالية(lcd 2*16 )
    أسلاك توصيل (Jumper wire) .
    لوحة تجارب (Breadborad)
     
    الدائرة الكهربائية :
     

     
    آلية عمل حساس الرطوبة والحرارة (DHT11) :
    لدى هذا الحساس القدرة على قراءة درجة الحرارة والرطوبة في البيئة المحيطة به .
     
    الفرق بين DHT11 و DHT22 :

     
    معلومات عن الشاشة الكربستالية :
    يوجد العديد من مقاسات الشاشات الكريستالية مثل 2*16 و 4*20  وفي هذا الدرس استخدمنا مقاس 2*16   وتعني إن الشاشة قادرة على عرض سطرين وكل سطر يحتوي على 16 حرف أو رمز.
     
    الكود البرمجي :
    في البداية نحتاج إلى إضافة مكتبة DHT  والتي تسهل علينا التعامل مع حساس الرطوبة والحرارة.
    أولا : نقوم بتحميل الملف المضغوط  .
    DHT library.zip
    ثانيا :نقوم بتشغيل برنامج Arduino IDE .
    ثالثا :نذهب إلى الشيفرة البرمجية ---< إدراج مكتبة  ---< أضف مكتبة ---< قم بإختيار الملف المضغوط .
    رابعا : قم بإغلاق البرنامج ثم إعد تشغيله .
     
    #include <LiquidCrystal.h> #include "DHT.h" LiquidCrystal lcd(8, 9, 10, 11, 12, 13); int DHTPIN =3; #define DHTTYPE DHT11 DHT dht(DHTPIN, DHTTYPE); void setup() { dht.begin(); lcd.begin(16, 2); } void loop() { int hum = dht.readHumidity(); int tem = dht.readTemperature(); lcd.setCursor(0, 0); lcd.print("Humidity: "); lcd.print(hum); lcd.setCursor(0, 1); lcd.print("Temperature: "); lcd.print(tem); delay(500); }  
    بعد رفع الكود للاردوينو أضف أحد مصادر الطاقة المذكورة في الدرس السابق لتنقل بها إلى أي مكان .

     
    شرح الكود البرمجي :
    #include <LiquidCrystal.h> تعريف بالمكتبة الخاصة بالشاشة الكريستالية
    #include "DHT.h" المكتبة الخاصة لمستشعر الحرارة والرطوبة
     
    LiquidCrystal lcd(8, 9, 10, 11, 12, 13); دالة تحمل أرقام المنافذ الاردوينو المتصلة بالشاشة الكريستالية .
     
    #define DHTTYPE DHT11 تعريف نوع مستشعر الحرارة والرطوبة المستخدم في درسنا وهو DHT11.
    لو كنت تستخدم نوع DHT22  فقط قم بإستبدال النوع في الكود السابق .
    DHT dht(DHTPIN, DHTTYPE); دالة لتهيئة الحساس وتحمل متغيرين متغير يحمل رقم المنفذ واخر نوع المستشعر .
     
    lcd.begin(16, 2); تعريف بمقاس الشاشة المستخدمة وهو 2*16 .
     
    int h = dht.readHumidity(); متغير لقراءة نسبة الرطوبة من المستشعر .
    int t = dht.readTemperature(); متغير لقراءة درجة الحرارة من المستشعر .
    lcd.setCursor(0, 0); هذه الدالة لجعل المؤشر في بداية السطر الاول.
    lcd.setCursor(0, 1); هذه الدالة لجعل المؤشر في بداية السطر الثاني.
     
    حل تحدي السابق :
    التحدي مذكور في هذا المقال

    يمكنك تحميل حل التحدي من هنا :
    waduino_3.ino
     
    تحدي بسيط :
    قم بجعل الشاشة تعرض فقط درجة الحرارة ثم تعرض درجة الرطوبة فقط لمدة 500 ملي ثانية لكل منهما .
    مستوى المقال: مبتدئ

    بواسطه وضاح العوني , في

  • بسم الله الرحمن الرحيم
    في هذا الموضوع سنقوم بمناقشة المواضيع التالية في التعامل مع صفوف الجداول :
    طريقة إخفاء الصفوف الفارغة في الجدول . طريقة إظهار الصفوف المطلوبة و إخفاء بعض الصفوف ( عن طريق تغيير ارتفاع الصف) .  
    ١- طريقة إخفاء الصفوف الفارغة في الجدول :
    سنقوم بعمل جدول وإضافة بعض القيم فيه ( بافتراض بأن لديك معرفه مسبقة لطريقة عمل الجداول) وهذا الجدول الذي قمت بعمله :

     
    نلاحظ بالجدول السابق وجود صفوف فارغة وقد تكون مزعجة نوعاً ما وقد نرغب في إخفائها :
     
    وحتى تقوم بإخفائها كل ماعليك هو اتباع إحدى الطرق التالية : 
    (لنفترض بأن TableView لدينا اسمه ColorTable)
     
    الطريقة الأولى : إخفاء الـ separator :
    باستخدام السطر التالي بداخل دالة viewDidLoad :
    ColorTable.separatorStyle = .none  
    أو من خلال Interface Builder للجدول ColorTable :

     
    وستكون النتيجة كالتالي :
     

     
    بالنسبة لهذه الطريقة فكما نلاحظ فقد تم إخفاء ال Separetor للجدول كامل .
     
    الطريقة الثانية : بإضافة Footer وجعل الارتفاع له يساوي 0 :
    وذلك بإضافة السطر التالي بداخل داله  viewDidLoad :
    ColorTable.tableFooterView = UIView(frame: .zero)  
    وستكون النتيجة كالتالي :
     

    الطريقة الثالثة : بإضافة UIView كـ Footer وذلك كالتالي :
     
    ١- قم بإضافة UIView أسفل الجدول كما في الصوره ( قمت بتغيير لون UIview للون الأزرق حتى تتضح لكم الفكرة) :


     
    ٢- بعد إضافة ال UIview قم بتغيير الارتفاع له بحيث يكون مساوياً لـ 0 وذلك من خلال Interface Builder:
     

     
    والنتيجة كالتالي :
     

     
    ٢- طريقة إظهار الصفوف المطلوبة و إخفاء بعض الصفوف :
    هذه الطريقة نستطيع الاستفاده منها في حاله أردنا إخفاء بعض الصفوف بشكل مؤقت ( وليست حذف للصفوف) وذلك عند تنفيذ أو حدوث أمر معين ، مثال على ذلك لو أردت إنشاء تقويم Calendar
    وتحت هذا التقويم ترغب بعرض الأحداث Events لذلك الشهر وإخفاءها في الشهور الأخرى :

     
    الفكرة هنا تكون من خلال تغيير الارتفاع للصف المطلوب وجعله مساوياً لل 0 ، ويتم عمل ذلك من خلال استخدام ال function التالية :
    public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { } سنقوم بتطبيق الفكره على جدولنا ColorTable  ونقوم بـ (إخفاء) اللون الأصفر من الجدول :
    النقاط المهمة لذلك هي :
    ١- انشاء الدالة التالية للتعامل مع ارتفاع صفوف الجدول :
    public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return } ٢- تعريف متغير من نوع CGFloat و تكون قيمته = 0.0 و هو يدل على قيمة الارتفاع للصف :
    var rowHeight:CGFloat = 0.0  
    ٣- نستخدم ال if - else وذلك للتحقق من الشرط الذي سيتم إخفاء الصفوف المطلوبة عند حدوثه وتحقق الشرط ففي حاله تحقق الشرط ستكون قيمة المتغير الذي تم تعريفه = 0.0
    وإذا لم يتحقق سنجعل ارتفاع الصفوف مثلاً = 60.0 :
     
    let RC = "Yellow" let cell1 = ColorTable.dequeueReusableCell(withIdentifier: "cell") cell1?.textLabel?.text = list[indexPath.row] if (RC == cell1?.textLabel?.text) { rowHeight = 0.0 }else { rowHeight = 60.0 } return rowHeight  
    الكود النهائي بداخل الدالة السابقة سيكون كالتالي :
     
    public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { var rowHeight:CGFloat = 0.0 let RC = "Yellow" let cell1 = ColorTable.dequeueReusableCell(withIdentifier: "cell") cell1?.textLabel?.text = list[indexPath.row] if (RC == cell1?.textLabel?.text) { rowHeight = 0.0 }else { rowHeight = 60.0 } return rowHeight }  
    وبذلك سيتم (إخفاء) اللون Yellow من القائمة :

     
    هذا مثال بسيط جداً لإخفاء الصفوف بشكل مؤقت دون حذفها فقط حتى تصل الفكرة لكم ..
     
    * خلاصة ماتعلمناه اليوم :
    طريقة إخفاء الصفوف الفارغة في الجدول : من خلال ٣ طرق :
    ١- إخفاء ال Separator :
    ColorTable.separatorStyle = .none ٢-  إضافة Footer وجعل الارتفاع له = 0 :
    ColorTable.tableFooterView = UIView(frame: .zero) ٣- إضافة UIView كـ Footer وجعل ارتفاعه =0 .
     
    طريقة إظهار الصفوف المطلوبة و إخفاء بعض الصفوف ( عن طريق تغيير ارتفاع الصف) . وذلك باستخدام الدالة التالية التي من خلالها نستطيع التحكم بقيمة ارتفاع الصفوف :
    public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { }  
    وبذلك نكون قد انتهينا اتمنى أن أكون قد وفقت في الشرح وتبسيط المعلومة لكم
    وأرحب بأي مناقشه وأي سؤال يخص الموضوع 🌹
    مستوى المقال: مبتدئ

    بواسطه ساره علي , في

  • Ads Belongs To 3llomi

    عالم البرمجة

    عالم البرمجة مقالات برمجة و دورات مجانية لإحتراف البرمجة هدفنا تبسيط البرمجة ونشرها بيد الكل بشكل ممتع ومتطور ومحدث بإستمرار لمواكبة جديد تطورات البرمجة الحديثة و المتقدمة بدون مقابل