بررسی نصب بودن برنامه در اندروید
در این جلسه از سری مباحث آموزش برنامه نویسی اندروید قصد دارم نحوه کنترل و بررسی نصب یا عدم نصب بودن برنامه در اندروید را با دو روش متفاوت بررسی کنم. به اینصورت که چک میکنیم آیا اپلیکیشنی با Package name مدنظر ما روی دستگاه اندرویدی قبلا نصب شده یا خیر.
همچنین در ادامه تعریف میکنیم چنانچه برنامه مدنظر روی سیستم عامل موجود نبود، صفحه مربوط به نصب نرم افزار در مارکت اندرویدی مانند پلی استور، کافه بازار و… و یا لینک آنرا در صفحه مرورگر پیش فرض باز کند.
در چه مواردی به بررسی نصب بودن برنامه در اندروید نیاز داریم؟
به نام خدا. گاهی اوقات بخشی از فرایندهای موجود در اپلیکیشن ما به یک یا چند برنامه دیگر وابسته است که در صورت نصب نبودن برنامه موردنظر روی دستگاه اندرویدی کاربر، میتواند سبب بروز اختلال در عملکرد برنامه ما گردد.
فرض کنید قصد توسعه و برنامه نویسی اپلیکیشنی را دارید که بخشی از امکانات آن با پرداخت درون برنامهای از طریق مارکتهای اندرویدی فعال میشود. در اینجا چنانچه مارکت موردنظر شما (مانند بازار، مایکت و…) روی دستگاه کاربر از قبل نصب و فعال نشده باشد، عملیات پرداخت ناتمام مانده و برنامه کرش خواهد کرد.
برای حل این مشکل لازم است شرطی را در برنامه تعریف کنیم که قبل از شروع فرایند پرداخت درون برنامهای، بررسی کند صرفا در صورتی این عملیات آغاز شود که مارکت با Package name مدنظر ما روی دستگاه موجود باشد و چنانچه موجود نبود، پیغامی با این مضمون را به کاربر نمایش داده و یا به صفحه دانلود مارکت هدایت شود.
به عنوان یک مثال دیگر، شرکت ارائه دهنده تاکسی آنلاین را درنظر بگیرید که دارای دو اپلیکیشن اندرویدی است. یک برنامه مخصوص مسافران و دیگری ویژهی رانندگان.
قصد داریم در هردو برنامه گزینهای برای انتقال به برنامه دیگر اضافه کنیم به طوری که اگر در اپ ویژهی مسافر، روی گزینه موردنظر کلیک شد، اپ ویژه راننده اجرا شده و بلعکس. و البته اینکه چنانچه برنامه دوم روی دستگاه نصب نبود، پیغام متناسب با آن نمایش داده شده و یا کاربر به صفحه نصب آن در مارکت یا مرورگر هدایت شود.
کاربردهای متعدد دیگری هم برای این قابلیت وجود دارد که در اینجا تنها به دو مورد اکتفا میکنم.
در ادامه مبحث در قالب یک پروژه ساده، این قابلیت را بررسی و تمرین میکنیم.
ساخت پروژه بررسی نصب بودن برنامه اندرویدی
طبق مبحث آموزش ساخت پروژه در اندروید استودیو یک پروژه اندرویدی با نام App installed میسازم. اکتیویتی را از نوع Empty Activity و زبان را Java انتخاب کردم.
ابتدا نحوه بررسی نصب بودن برنامه در اندروید را به دو روش متفاوت انجام و در مرحله آخر نیز فراخوانی مارکت و یا باز کردن لینک صفحه دانلود برنامه را بررسی میکنیم.
روش اول: استفاده از متد getPackageInfo
در روش نخست، با استفاده از متد getPackageInfo و دستور try catch در لیست برنامههای نصب شده روی دستگاه اندرویدی نام پکیج برنامه مدنظر را جستجو میکنیم. چنانچه نام پکیج یا همان Package name موردنظر موجود بود کدهای درون بلاک try و در غیر اینصورت قسمت catch اجرا خواهد شد:
private boolean installedOrNot(Context cnt, String packageName) { PackageManager pm = cnt.getPackageManager(); boolean appInstalled; try { pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES); appInstalled = true; Toast.makeText(cnt, "برنامه قبلا نصب شده است", Toast.LENGTH_LONG).show(); } catch (PackageManager.NameNotFoundException e) { appInstalled = false; Toast.makeText(cnt, " برنامه قبلا نصب نشده است ", Toast.LENGTH_LONG).show(); } return appInstalled; }
مطابق با کد فوق ابتدا یک متد از جنس boolean و با نام دلخواه installedOrNot درون اکتیویتی و بعد از متد onCreate تعریف کردهام. این متد دو پارامتر دارد که اولی کانتکست و دومی از جنس رشته تعریف شده.
درون این متد ابتدا یک شیء از کلاس PackageManager با نام دلخواه pm ساخته شده است. سپس یک متغیر از جنس boolean با نام appInstalled تعریف شده.
داخل بلاک try و با استفاده از متد getPackageInfo نام پکیج بررسی میشود. چنانچه پکیج و به عبارتی اپلیکیشن مدنظر قبلا نصب شده باشد، متغیر appInstalled مقدار true گرفته و کدهای بعد از آن اجرا میشود که من در اینجا یک پیغام Toast تعریف کردم.
برای بلاک catch یک Exception (استثناء) از نوع PackageManager.NameNotFoundException تعریف شده که از نامش پیداست مربوط به پیدا نشدن نام است (NameNotFound). یعنی هنگامی که نام پکیج یافت نشد این استثناء اجرا میشود که در اینصورت مقدار false برای متغیر appInstalled در نظر گرفته شده و مانند قسمت قبل یک پیغام برای کاربر ظاهر میشود که اعلام میکند برنامه مدنظر نصب نشده است.
در نهایت از آنجایی که تابع از جنس boolean بود لازم است appInstalled را return کنیم.
حالا متد را در onCreate تعریف میکنم:
installedOrNot(getApplicationContext(), "com.farsitel.bazaar");
پارامتر نخست مربوط به کانتکست است که قبلا آشنا شدیم و نیاز به توضیح مجدد نیست. برای پارامتر دوم نام پکیج موردنظرم را در قالب یک String وارد میکنم. من Package name مارکت ایرانی بازار را تعریف کردهام. تا اینجای کار اکتیویتی ما به صورت زیر تکمیل شده است:
MainActivity.java
package ir.android_studio.appinstalled; import androidx.appcompat.app.AppCompatActivity; import android.content.Context; import android.content.pm.PackageManager; import android.os.Bundle; import android.widget.Toast; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); installedOrNot(getApplicationContext(), "com.farsitel.bazaar"); } private boolean installedOrNot(Context cnt, String packageName) { PackageManager pm = cnt.getPackageManager(); boolean appInstalled; try { pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES); appInstalled = true; Toast.makeText(cnt, "برنامه قبلا نصب شده است", Toast.LENGTH_LONG).show(); } catch (PackageManager.NameNotFoundException e) { appInstalled = false; Toast.makeText(cnt, "برنامه قبلا نصب نشده است", Toast.LENGTH_LONG).show(); } return appInstalled; } }
خب! پروژه را اجرا و تست میکنیم:
به محض اجرای برنامه روی شبیه ساز، پیغام “برنامه قبلا نصب نشده است” مشاهده شد. یعنی اپلیکیشن بازار روی این دیوایس نصب نیست.
حالا برنامه بازار را روی دستگاه نصب کرده و مجدد پروژه را اجرا میکنم:
برخلاف قسمت قبل اینبار پیغام “برنامه قبلا نصب شده است” ظاهر شد. بنابراین کد ما به درستی عمل میکند.
برای مثال پرداخت درون برنامهای که در ابتدای مبحث عنوان شد، بجای Toast اول میتوانیم عملیات مربوط به انتقال به مارکت و ثبت تراکنش مالی توسط کاربر را انجام دهیم. همچنین بجای Toast دوم هم میتوان کاربر را به صفحه دانلود مارکت هدایت کرد یا اینکه در قالب همین پیغام اعلام شود لازم است مارکت x روی دستگاه نصب شود. این بخش را نیز در انتهای مبحث بررسی میکنیم.
روش دوم: استفاده از intent
قبلا در جلسه آموزش intent در اندروید با اینتنتها آشنا شدیم. در این روش با استفاده از intent، نام پکیج کلیه برنامههای نصب شده روی دستگاه اندرویدی را در یک لیست ذخیره کرده و سپس پکیج موردنظر را درون آن لیست جستجو میکنیم.
ابتدا کد مربوط به قسمت قبل را کامنت میکنم تا غیر فعال شود. سپس دو متد به صورت زیر به اکتیویتی اضافه میکنم:
protected List<String> getInstalledAppsPackage() { Intent mIntent = new Intent(Intent.ACTION_MAIN, null); mIntent.addCategory(Intent.CATEGORY_LAUNCHER); mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); List<ResolveInfo> resolveInfoList = getPackageManager().queryIntentActivities(mIntent, 0); List<String> packageNameList = new ArrayList<>(); for (ResolveInfo resolveInfo: resolveInfoList) { ActivityInfo actInfo = resolveInfo.activityInfo; packageNameList.add(actInfo.applicationInfo.packageName); } return packageNameList; } private void appStatus() { final List<String> installedPackages = getInstalledAppsPackage(); if (installedPackages.contains(mPackageName)) { Toast.makeText(this, "برنامه قبلا نصب شده است", Toast.LENGTH_LONG).show(); } else { Toast.makeText(this, "برنامه قبلا نصب نشده است", Toast.LENGTH_LONG).show(); } }
ملاحظه میکنید ابتدا یک تابع از جنس List
در ادامه کار یک متد دیگر با نام دلخواه appStatus تعریف شده که درون آن بررسی میکنیم آیا این لیست شامل mPackageName ای که تعریف کردهایم هست (contains) یا نه. چنانچه این شرط برقرار بود، پیغام نصب و در غیر اینصورت پیغام عدم نصب نمایش داده خواهد شد.
در نهایت، متد appStatus را در onCreate فراخوانی میکنم.
برای تست این کد، نام پکیج مربوط به پلیر VLC را در بدنه اکتیویتی تعریف میکنم:
private String mPackageName = "org.videolan.vlc";
تا اینجای کار اکتیویتی به صورت زیر تکمیل شده است:
MainActivity.java
package ir.android_studio.appinstalled; import androidx.appcompat.app.AppCompatActivity; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Bundle; import android.widget.Toast; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private String mPackageName = "org.videolan.vlc"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // installedOrNot(getApplicationContext(), "com.farsitel.bazaar"); appStatus(); } /* private boolean installedOrNot(Context cnt, String packageName) { PackageManager pm = cnt.getPackageManager(); boolean appInstalled; try { pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES); appInstalled = true; Toast.makeText(cnt, "برنامه قبلا نصب شده است", Toast.LENGTH_LONG).show(); } catch (PackageManager.NameNotFoundException e) { appInstalled = false; Toast.makeText(cnt, " برنامه قبلا نصب نشده است", Toast.LENGTH_LONG).show(); } return appInstalled; } */ protected List<String> getInstalledAppsPackage() { Intent mIntent = new Intent(Intent.ACTION_MAIN, null); mIntent.addCategory(Intent.CATEGORY_LAUNCHER); mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); List<ResolveInfo> resolveInfoList = getPackageManager().queryIntentActivities(mIntent, 0); List<String> packageNameList = new ArrayList<>(); for (ResolveInfo resolveInfo: resolveInfoList) { ActivityInfo actInfo = resolveInfo.activityInfo; packageNameList.add(actInfo.applicationInfo.packageName); } return packageNameList; } private void appStatus() { final List<String> installedPackages = getInstalledAppsPackage(); if (installedPackages.contains(mPackageName)) { Toast.makeText(this, "برنامه قبلا نصب شده است", Toast.LENGTH_LONG).show(); } else { Toast.makeText(this, "برنامه قبلا نصب نشده است", Toast.LENGTH_LONG).show(); } } }
با اجرای مجدد پروژه، پیغام عدم نصب نمایش داده خواهد شد زیرا این پلیر روی دستگاه نصب نیست.
در قسمت بعد نحوه هدایت کاربر به صفحه نصب یا دریافت برنامه را بررسی میکنیم.
هدایت کاربر به صفحه نصب برنامه در مارکت یا یک صفحه وب
چنانچه قصد داشته باشیم برای راحتی کاربر، در صورت نصب نبودن برنامه مورد نیاز به سرعت او را به صفحه دریافت و نصب برنامه هدایت کنیم، با استفاده از یک دستور try catch این کار را انجام میدهیم. قصد دارم برای روش دوم که مربوط به برنامه VLC بود، کدی را بنویسم که در صورت نصب نبودن آن، ابتدا صفحه مربوط به آن در مارکت اندرویدی پیش فرض روی دستگاه باز شده و چنانچه مارکتی وجود نداشت، کاربر به یک آدرس اینترنتی هدایت شود.
یک متد دیگر با نام installApp به اکتیویتی اضافه کرده و به صورت زیر تکمیل میکنم:
private void installApp() { try { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + mPackageName))); } catch (android.content.ActivityNotFoundException ane) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + mPackageName))); } }
برای انتقال کاربر به صفحه معرفی یک برنامه در مارکتهای اندرویدی، uri به صورت
market://details?id=PACKAGE_NAME
تعریف میشود. برای قسمت دوم شرط هم من صفحه معرفی برنامه در پلی استور را قرار دادم. نحوه تعیین آدرس صفحه برنامهها در پلی استور به اینصورت است:
https://play.google.com/store/apps/details?id=PACKAGE_NAME
حالا متد را در قسمت دوم شرط مربوط به appStatus فراخوانی میکنم:
if (installedPackages.contains(mPackageName)) { Toast.makeText(this, "برنامه قبلا نصب شده است", Toast.LENGTH_LONG).show(); } else { Toast.makeText(this, "برنامه قبلا نصب نشده است", Toast.LENGTH_LONG).show(); installApp(); }
دوباره پروژه را اجرا میکنم. با توجه به نصب نبودن پلیر VLC روی این دیوایس، صفحه نصب آن در مارکت بازار باز شد:
فروشگاه پلی استور به صورت پیش فرض روی دیوایسهای شبیه ساز اندرویدی Genymotion نصب نیست و با توجه به اینکه در قسمت نخست آموزش، برنامه کافه بازار را نصب کرده بودیم، در اینجا صفحه نصب پلیر VLC در این مارکت باز شد.
در قدم نهایی، مارکت کافه بازار را حذف و پروژه را مجدد اجرا میکنم:
مشاهده میکنید صفحه معرفی و نصب برنامه در play.google.com در مرورگر دستگاه باز شد.
کد نهایی اکتیویتی:
MainActivity.java
package ir.android_studio.appinstalled; import androidx.appcompat.app.AppCompatActivity; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Bundle; import android.widget.Toast; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private String mPackageName = "org.videolan.vlc"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // installedOrNot(getApplicationContext(), "com.farsitel.bazaar"); appStatus(); } /* private boolean installedOrNot(Context cnt, String packageName) { PackageManager pm = cnt.getPackageManager(); boolean appInstalled; try { pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES); appInstalled = true; Toast.makeText(cnt, " برنامه قبلا نصب نشده است", Toast.LENGTH_LONG).show(); } catch (PackageManager.NameNotFoundException e) { appInstalled = false; Toast.makeText(cnt, "برنامه قبلا نصب نشده است", Toast.LENGTH_LONG).show(); } return appInstalled; } */ protected List<String> getInstalledAppsPackage() { Intent mIntent = new Intent(Intent.ACTION_MAIN, null); mIntent.addCategory(Intent.CATEGORY_LAUNCHER); mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); List<ResolveInfo> resolveInfoList = getPackageManager().queryIntentActivities(mIntent, 0); List<String> packageNameList = new ArrayList<>(); for (ResolveInfo resolveInfo: resolveInfoList) { ActivityInfo actInfo = resolveInfo.activityInfo; packageNameList.add(actInfo.applicationInfo.packageName); } return packageNameList; } private void appStatus() { final List<String> installedPackages = getInstalledAppsPackage(); if (installedPackages.contains(mPackageName)) { Toast.makeText(this, "برنامه قبلا نصب شده است", Toast.LENGTH_LONG).show(); } else { Toast.makeText(this, "برنامه قبلا نصب نشده است", Toast.LENGTH_LONG).show(); installApp(); } } private void installApp() { try { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + mPackageName))); } catch (android.content.ActivityNotFoundException ane) { startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + mPackageName))); } } }
موفق و پیروز باشید.
مطالعهی بیشتر:
https://developer.android.com/reference/android/content/pm/ResolveInfo
https://developer.android.com/reference/android/content/pm/PackageManager
https://developer.android.com/reference/android/content/Intent
توجه : سورس پروژه درون پوشه Exercises قرار دارد
تعداد صفحات : ۱۴
حجم : ۱ مگابایت
قیمت : رایگان
دانلود رایگان با حجم ۱ مگابایت لینک کمکی
سلام.
این کد market://details?id=PACKAGE_NAME
برای هر مارکتی همین هست یا اینکه مثلا بین کافه بازار و مایکت یا یه مارکت دیگه تفاوت داره؟
https://developers.cafebazaar.ir/fa/docs/bazaar-services-intent
سلام خسته نباشید
خیلی وقته آموزش جدیدی نمیزارید
سلام. ممنون که پیگیر هستید. یه مقدار درگیر بروز کردن سایت و آموزشهای قبلی و بقیه کارام شدم این چند مدت. ان شا الله به زودی مباحث جدید رو شروع می کنم