در این مبحث به نحوهی ایمپورت پروژههای اندروید (اکلیپس و اندروید استودیو) در اندروید استودیو و انواع روشهای آن پرداخته شده است.
به نام خدا. برای ما به عنوان برنامه نویس و توسعه دهنده اندروید، استفاده از سورسها و پروژههایی که سایر افراد نوشته و منتشر کردهاند اجتناب ناپذیر است. یا ممکن است پروژهی اندرویدی که خودمان مدتها قبل نوشتیم را باید مجدد ویرایش کرده و نسخه جدید اپلیکیشن را به کاربران عرضه کنیم. برای استفاده مجدد از یک سورس در محیط اندروید استودیو ابتدا باید پروژه را ایمپورت (وارد) کنیم.
اندروید استودیو را اجرا میکنم:
۳ گزینه از گزینههای صفحه ورودی اندروید استودیو مربوط به import کردن سورس است:
- Open an existing Android Studio project: از این گزینه برای ایمپورت کردن پروژههایی استفاده میشود که قبلا توسط همین محیط توسعه یعنی اندروید استودیو ساخته شده اند.
- Import project (Gradle, Eclipse ADT): پروژههایی که در محیطی غیر از اندروید استودیو (مانند اکلیپس) ساخته شدهاند از طریق این قسمت باید ایمپورت شوند.
- Import an Android code sample: از این گزینه برای وارد کردن نمونه کدهای اندروید استفاده میشود.
تفاوت پروژهی ساخته شده در محیط اکلیپس و اندروید استودیو
احتمالا اولین سوالی که به ذهنتان رسید این است که تفاوت یک پروژه ساخته شده در محیط توسعه Eclipse با پروژهای که توسط Android Studio ایجاد شده در چیست و چطور باید تشخیص بدهیم پروژهای که از یک وب سایت دانلود کردهایم در کدام محیط توسعه ساخته شده؟
تشخیص بسیار ساده است. کافی است به ساختار پروژه نگاه بیندازید. به دو تصویر زیر دقت کنید:
تصویر نخست مربوط به یک پروژه اکلیپس است در حالی که تصویر دوم یک پروژه ساخته شده در اندروید استودیو را نشان میدهد. واضحترین تفاوت این دو، وجود فولدر و فایلهایی است که در نامگذاری آنها کلمه gradle بکار رفته. با بیلد سیستم گریدل در مباحث ابتدایی آشنا شدیم و میدانیم این بیلد سیستم در اندروید استودیو بکار رفته بنابراین پروژهای که حاوی فایلهای مرتبط با gradle باشد در محیط اندروید استودیو ساخته شده و در غیر اینصورت مربوط به اکلیپس است.
import کردن پروژهی اندروید استودیو
قصد دارم یک پروژه که قبلا در محیط اندروید استودیو ساخته شده را ایمپورت کنم. برای اینکار از سورس پروژه مبحث SharedPreferences که حدودا یک سال قبل از تهیه این مبحث آموزشی ساخته شده استفاده میکنم.
روی Open an existing Android Studio project کلیک کرده و فولدر Preference را انتخاب میکنم:
مشاهده میکنید آیکون اندروید استودیو در کنار نام فولدر مربوط به پروژه نمایش داده میشود یعنی ساختار این پروژه مربوط به اندروید استودیو است. در حالی که آیکون پروژه ExpandableListView یک فولدر معمولی ست.
با انتخاب پروژه و تایید آن، محیط اندروید استودیو باز میشود و پروژه در حال بیلد شدن است. در قسمت Build جزئیات مربوط به بیلد شدن پروژه لیست میشود.
در اولین مرحله اندروید استودیو در حال دانلود gradle-3.3-all.zip است که حجمی حدود ۸۰ مگابایت دارد. در صورتی که گریدل قبلا روی اندروید استودیوی من نصب شده و چندین پروژه ساختهام. علت در قدیمی بودن سورس پروژه است. از زمانی که این پروژه ساخته شده حدودا یک سال میگذرد و در طی این مدت چند نسخه جدیدتر از گریدل معرفی و در حال حاضر آخرین نسخه از آن روی سیستم من نصب شده.
اینجا دو انتخاب دارم. یا پروژه را ایمپورت کنم و اجازه دهم دانلود نسخه قدیمی گریدل به اتمام برسد و پروژه بر اساس همان نسخه بیلد شود یا قبل از ایمپورت کردن پروژه، ورژن گریدل را مطابق نسخه نصب شده در اندروید استودیو تغییر دهم.
به دو دلیل انتخاب منطقی گزینه دوم است. اول از این جهت که نسخه گریدل را به نسخه نهایی تغییر میدهم و عمل بیلد توسط جدیدترین نسخه انجام میشود و نه یک نسخه قدیمی. دوم اینکه نیاز به دانلود یک فایل چند ده مگابایتی را مرتفع میکند.
بنابراین فعلا پروژه را میبندم (close project) و فولدر پروژه را باز میکنم:
تذکر: این تغییرات را بعد از ایمپورت کردن پروژه و در محیط اندروید استودیو هم میتوان انجام داد اما من ترجیح میدهم قبل از اینکه سراغ اندروید استودیو بروم، ابتدا پروژه را اصلاح کنم تا بعد از ایمپورت نیاز به کنسل کردن دانلود گریدل و اصلاح پروژه نشوم. این کاملا به سلیقه فرد بستگی دارد.
فایل build.gradle را با یک ادیتور ساده مانند ++Notepad باز میکنم:
buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.3.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { jcenter() } } task clean(type: Delete) { delete rootProject.buildDir }
در خط ۶ پلاگین گریدل نسخه ۲٫۳٫۳ تعریف شده که نسخه قدیمی است. برای پیدا کردن نسخهای که در حال حاضر روی سیستم نصب شده، ساده ترین راه، باز کردن build.gradle پروژهای است که اخیرا ساختهایم:
buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.2.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { google() jcenter() } } task clean(type: Delete) { delete rootProject.buildDir }
در این پروژه گریدل نسخه ۳٫۲٫۱ تعریف شده بنابراین این عدد را کپی کرده و در build.gradle پروژه هدف جایگزین عدد ۲٫۳٫۳ میکنم.
همچنین در نسخه جدید اندروید استودیو در بلاک repositories در buildscript و allprojects یک ریپازیتوری (مخزن) جدید به نام google() اضافه شده. بنابراین این دو مورد را نیز اضافه میکنم تا هنگام ایمپورت شدن پروژه اروری به دلیل عدم دسترسی به مخزن گوگل بوجود نیاید.
در واقع من فایل build.gradle پروژه جدید را جایگزین build.gradle پروژه قدیمی کردم.
سپس فایل gradle-wrapper.properties در مسیر gradle>wrapper دو پروژه را مقایسه میکنم:
ورژن گریدل در پروژه جدید ۴٫۶ و در پروژه قدیمی ۳٫۳ است. پس این ورژن را اصلاح میکنم (به عبارتی نام فایل zip باید همنام با فایل موجود در پروژه فعلی باشد).
در مرحله بعد باید فایل build.gradle درون فولدر app پروژه را اصلاح کنم.
این همان build.gradle (Module:app) است. فایل را باز میکنم:
apply plugin: 'com.android.application' android { compileSdkVersion 25 buildToolsVersion "26.0.0" defaultConfig { applicationId "ir.android_studio.preference" minSdkVersion 10 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.3.1' compile 'com.android.support.constraint:constraint-layout:1.0.2' testCompile 'junit:junit:4.12' }
جزئیات مربوط به این فایل را قبلا در مبحث ساخت فایل APK توضیح دادهام. مانند مرحله قبل، فایل build.gradle فولدر app پروژهای که جدیدا ساختهام را باز میکنم:
apply plugin: 'com.android.application' android { compileSdkVersion 28 defaultConfig { applicationId "com.example.mahdi.testproject" minSdkVersion 19 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' }
در بلاک android پارامترهای compileSdkVersion و targetSdkVersion در دو فایل متفاوت هستند. اگر بخواهم پروژهای که قصد ایمپورت آن را دارم با آخرین API کامپایل شود و نسخه هدف (target) نیز جدیدترین API باشد، عدد هردو پارامتر را مطابق پروژه جدید اصلاح میکنم. همچنین پارامتر buildToolsVersion در نسخه ۳ اندروید استودیو حذف شده بنابراین آنرا هم از build.gradle حذف میکنم (حذف کردن یا نکردن این مورد مهم نیست و خود اندروید استودیو تغییرات را مدیریت میکند اما من ترجیح میدهم قبلا از ایمپورت، پروژه بیشترین هماهنگی را با ساختار جدید و مدنظرم داشته باشد).
minSdkVersion هم نیاز به توضیح ندارد.
در بلاک dependencies نیز تفاوتهایی بین دو پروژه به چشم میخورد. نسخهی کتابخانههای زیرمجموعه com.android.support مانند appcompat-v7 باید مطابق نسخهی compileSdkVersion باشد. من این پارامتر را از ۲۵ به ۲۸ تغییر دادم بنابراین نسخهی کتابخانههای support نیز باید اصلاح شود.
همچنین نسخه کتابخانه constraint-layout را اصلاح میکنم.
حتما با مشکلات تحریم آیپی ایران در اندروید استودیو دست و پنجه نرم کردهاید. برای رفع این محدودیت مطلب دور زدن تحریمهای نرم افزاری را مطالعه کنید. با وجود امکان رفع محدودیت در دانلود کتابخانهها، من ترجیح میدهم کتابخانههای اضافی که مطمئن هستم در پروژه نقشی ندارند و یا وجودشان برای من لازم نیست را حذف کنم. مانند junit و espresso-core.
آخرین تفاوت مربوط به کلمه compile است. در نسخه جدید اندروید استودیو کتابخانهها به جای compile شدن، implementation میشوند. البته عملکرد هردو یکی است فقط در جزئیات تفاوت دارد.
در نهایت فایل build.gradle (فولدر app) پروژه به اینصورت اصلاح شد:
apply plugin: 'com.android.application' android { compileSdkVersion 28 defaultConfig { applicationId "ir.android_studio.preference" minSdkVersion 19 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' }
هردو فایل build.gradle و همچنین gradle-wrapper.properties پروژه را اصلاح کردم.
حالا توسط گزینه Open an existing Android Studio project پروژه را ایمپورت میکنم:
پروژه بدون کوچکترین اخطار و بدون اینکه نیاز به دانلود نسخهای از گریدل یا کتابخانهها باشد ایمپورت شد.
البته نباید انتظار داشت در پروژههای سنگین هم همین نتیجه را گرفت. در پروژههای واقعی و غیر آموزشی که عموما از کتابخانههای مختلف استفاده شده به احتمال زیاد نیاز به دانلود چند کتابخانه هست. با اینحال بخشی از ارورها رفع میشود.
باز هم تاکید میکنم اینکه قبل از ایمپورت پروژه را اصلاح کنیم یا نه کاملا به سلیقه و میل شخص توسعه دهنده بستگی دارد. میتوان پروژه را مستقیما ایمپورت کرد و تغییرات را در همان محیط انجام داد. ولی من ترجیح میدهم تغییرات را در محیطی خارج از محیط توسعه انجام دهم و بعد از ایمپورت کمتر با ارورها مواجه شوم.
نکته: همیشه نیازی به ایمپورت کردن پروژهها نیست. برخی سورسها (از جمله سورس پروژههای آموزشی موجود در سایت ما) معمولا صرفا یک یا دو اکتیویتی دارند که بجای ایمپورت آن میتوان یک پروژه جدید ساخت و محتوای اکتیویتیها و همچنین کتابخانههای بکار رفته را با محتوای پیش فرض پروژه (فایلهای xml و java) جایگذاری کرد.
نکته: ممکن است هیچگاه گذرتان به پروژههای اکلیپسی نخورد. با اینحال توصیه میکنم چند دقیقه وقت را به مطالعه قسمت بعد اختصاص دهید تا دلیل اصلاحاتی که قبل از ایمپورت پروژه انجام دادم برایتان ملموستر شود.
import کردن پروژهی اکلیپس (ADT) در اندروید استودیو
در اوایل سال ۲۰۱۹ که من این آموزش را تهیه میکنم کمتر پروژهای میتوان در اینترنت پیدا کرد که مربوط به اکلیپس باشد. با اینحال وظیفه خودم دانستم برای آن چند درصد باقیمانده هم وقت بگذارم. برای این قسمت من از یک پروژه تحت اکلیپس که چند سال قبل از یک وب سایت آموزشی انگلیسی زبان دانلود کرده بودم استفاده میکنم.
میخواهم یک پروژه که در محیط توسعه اکلیپس یا همان ADT ساخته شده را ایمپورت کنم:
روی Import project کلیک کرده، فولدر مربوط به پروژه اکلیپس را انتخاب میکنم:
بر خلاف قسمت قبل، اندروید استودیو برای ایمپورت پروژههای اکلیپس یک مسیر جدید ایجاد میکند و پوشهی اصلی پروژه بدون تغییر باقی میماند. اندروید استودیو در حین ایمپورت، تغییرات لازم برای سازگاری پروژه قدیمی با محیط توسعه جدید را بطور خودکار انجام میدهد. مانند اضافه کردن فایلهای مربوط به بیلد سیستم گریدل و… .
در این مرحله چند آپشن وجود دارد که همگی تیک خورده و ایده آل هم همین است. به عنوان مثال گزینه اول فایل محلی کتابخانهها را با نسخه آنلاین جایگزین میکند.
با شروع بیلد شدن پروژه یک ارور گرفتم:
علت ارور این است که در پروژه فقط ریپازیتوری jcenter() تعریف شده. در ادامه گفته برای رفع مشکل باید Google Maven Repository() را به پروژه اضافه کرده و مجدد سینک کنید. با کلیک روی خط
Add Google Maven… این کار انجام میشود. یعنی مخزن google() به build.gradle اضافه میشود. دقیقا همان کاری که در قسمت قبل به طور دستی و قبل از ایمپورت پروژه در محیط Notepad++ انجام دادم!
گزینه Add را زدم و این ارور رفع شد. بلافاصله یک ارور دیگر ظاهر میشود:
این ارور میگوید API 17 در SDK من موجود نیست. همینطور هم هست! من از آخرین API یعنی نسخه ۲۸ استفاده میکنم و نیازی به نسخه ۱۷ ندارم.
حالا دو انتخاب دارم. یا API 17 را نصب کنم یا عدد ۱۷ را به ۲۸ تغییر دهم. راه منطقی باز هم گزینه دوم است زیرا در حال حاضر توجیهی ندارد بخواهم پروژه را با یک API مربوط به چند سال گذشته بیلد کنم. بنابراین build.gradle فولدر app را باز میکنم:
compileSdkVersion و targetSdkVersion (و اگر نیاز بود minSdkVersion) را اصلاح و سپس Sync میکنم:
و اما ارور بعد!
ارور اول مربوط به جایگزینی compile با implementation است که در قسمت گذشته، قبل از ایمپورت انجام دادم.
در این پروژه کتابخانه support-v4 استفاده شده:
dependencies { compile 'com.android.support:support-v4:18.0.0' }
به اینصورت اصلاح و سینک میکنم:
dependencies { implementation 'com.android.support:support-v4:18.0.0' }
در ارور دوم این نکته بیان شده که targetSdk نباید در AndroidManifest.xml تعریف شود.
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="info.androidhive.expandablelistview" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="info.androidhive.expandablelistview.MainActivity" android:label="@string/app_name" android:theme="@android:style/Theme.Holo.Light.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
در گذشته این اطلاعات در مانیفست تعریف میشد که اکنون به build.gradle منتقل شده. بنابراین تگ زیر را از مانیفست حذف میکنم:
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" />
بهتر است versionCode، versionName و package را هم از مانیفست حذف کنم. همه این موارد به گریدل منتقل شده.
فایل نهایی مانیفست:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="info.androidhive.expandablelistview.MainActivity" android:label="@string/app_name" android:theme="@android:style/Theme.Holo.Light.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
حالا با سینک کردن پروژه خطای بیلد نمیگیرم. تغییراتی که در طی پروسه تبدیل پروژه به یک پروژه سازگار با محیط توسعه جدید لحاظ شده در فایل import-summary.txt لیست شده است.