Dagger Java اور Kotlin کے لیے ایک انحصاری انجیکشن فریم ورک ہے جو تشریحی پروسیسنگ کے ذریعے مرتب وقت پر DI کوڈ تیار کرتا ہے۔ Hilt Android کے لیے Dagger کے اوپر ایک لفافہ ہے جو اجزاء کی ترتیب اور زندگی کے چکر کے انتظام کو آسان بناتا ہے۔ Google، 2025 کے مطابق، Google Play Top-100 میں سے 70% سے زیادہ Android ایپس میں Hilt استعمال ہوتا ہے، جو پہلے سے طے شدہ اجزاء کے ذریعے Activity، Fragment، ViewModel اور Service کو سپورٹ کرتا ہے۔ دونوں فریم ورک مرتب وقت پر انحصاری گراف کی تصدیق فراہم کرتے ہیں، رن ٹائم انجیکشن کی غلطیوں کو ختم کرتے ہیں۔
اہم نکات
Dagger ایک انحصاری انجیکشن فریم ورک ہے جس میں مرتب وقت کوڈ جنریشن ہے۔ اصل میں Square میں تیار کیا گیا اور بعد میں Google کو منتقل کیا گیا، Dagger انحصاری گراف کا تجزیہ کرنے اور فیکٹری کلاسز تیار کرنے کے لیے Java APT تشریحی پروسیسر استعمال کرتا ہے۔ رن ٹائم DI (Guice، Koin) کے برعکس، Dagger ریفلیکشن استعمال نہیں کرتا — تمام کوڈ مرتب وقت پر بنایا جاتا ہے، جو رن ٹائم میں زیادہ سے زیادہ کارکردگی اور تعمیر کے وقت خرابی کا پتہ لگانے کو یقینی بناتا ہے۔
Hilt ایک Google لائبریری ہے جو Dagger کے اوپر بنائی گئی ہے اور Android کے لیے بہتر بنائی گئی ہے۔ Hilt Android اجزاء کے زندگی کے چکر کے مطابق پہلے سے طے شدہ اجزاء فراہم کرتی ہے: Application کے لیے @SingletonComponent، Activity کے لیے @ActivityComponent، Fragment کے لیے @FragmentComponent، ViewModel کے لیے @ViewModelComponent۔ یہ خالص Dagger میں درکار معمول کے Component اور Module کنفیگریشن کو ختم کرتا ہے۔ Hilt @AndroidEntryPoint کے ذریعے ہر Android جزو کے لیے خود بخود انحصاری گراف بھی تیار کرتی ہے۔
Google I/O 2024 کے مطابق، Kotlin میں لکھی گئی Android ایپلیکیشنز میں DI کے لیے Hilt تجویز کردہ حل ہے۔ Jetpack لائبریریاں (Navigation، Room، WorkManager) @HiltViewModel اور @HiltWorker کے ذریعے Hilt کے ساتھ بلٹ ان انضمام رکھتی ہیں۔ ان پروجیکٹس میں جو Android استعمال نہیں کرتے (خالص Java/Kotlin لائبریریاں، سرور ایپلیکیشنز)، Hilt لفافے کے بغیر خالص Dagger استعمال کیا جاتا ہے۔
DI فریم ورک کے بغیر، ڈویلپر کنسٹرکٹرز یا فیکٹریوں کے ذریعے دستی طور پر اشیاء بناتا ہے، زنجیر کے ساتھ انحصاریں منتقل کرتا ہے۔ ہر نئی ضرورت کا مطلب زنجیر میں تمام کنسٹرکٹرز کے دستخط تبدیل کرنا ہے۔ Dagger اس عمل کو خودکار بناتا ہے: آپ صرف اعلان کرتے ہیں کہ کس قسم کی ضرورت ہے (@Inject constructor)، اور Dagger تمام نیسٹڈ اقسام کو حل کرتے ہوئے انحصاری گراف بناتا ہے۔ جب انحصاریاں تبدیل ہوتی ہیں، Dagger خود بخود تیار کردہ کوڈ کو اپ ڈیٹ کرتا ہے — زنجیر میں غلطی کرنا ناممکن ہے۔
انحصاری انجیکشن ایک نمونہ ہے جس میں ایک شے اپنی انحصاریاں خود بنانے کے بجائے باہر سے حاصل کرتی ہے۔ DI کنٹرول کے الٹ (IoC) کے اصول کو نافذ کرتا ہے: ایک کلاس اپنی انحصاریاں بنانے کی ذمہ دار نہیں ہے، بلکہ انہیں کنسٹرکٹر، طریقہ یا فیلڈ کے ذریعے ظاہر کرتی ہے۔ کنسٹرکٹر انجیکشن کو سب سے زیادہ ترجیح دی جاتی ہے کیونکہ یہ یقینی بناتا ہے کہ شے ایک درست حالت میں بنائی گئی ہے۔
| انجیکشن کی قسم | Dagger نحو | کب استعمال کریں |
|---|---|---|
| Constructor injection | @Inject constructor | بنیادی طریقہ — تمام حسب ضرورت کلاسز کے لیے |
| Field injection | @Inject lateinit var | صرف Android اجزاء کے لیے (Activity، Fragment) |
| Method injection | @Inject fun bind() | تشکیل کے بعد ابتدائیہ کے لیے |
DI کے اہم فوائد میں جانچ کی اہلیت (انحصاریوں کو نقلی اشیاء سے تبدیل کیا جا سکتا ہے)، ڈھیلا جوڑ (کلاسیں نفاذ پر نہیں بلکہ انٹرفیس پر منحصر ہوتی ہیں)، اور دائروں کے ذریعے اشیاء کے زندگی کے چکر کا واضح انتظام شامل ہے۔ Dagger خود بخود ضمانت دیتا ہے کہ ایک شے اپنے دائرہ کار میں ایک بار بنائی جاتی ہے اور دائرہ کار سے باہر نکلنے پر تباہ کر دی جاتی ہے۔
Component Dagger انحصاری گراف کا مرکزی عنصر ہے۔ یہ @Component سے نشان زدہ ایک انٹرفیس ہے جو Module اور انجیکشن اہداف کے درمیان پل کو بیان کرتا ہے۔ Dagger مرتب وقت پر Component کا نفاذ (مثلاً DaggerAppComponent) تیار کرتا ہے۔ Component اس بات کا تعین کرتا ہے کہ مطلوبہ اقسام واپس کرنے والے تجریدی طریقوں یا فیلڈ انجیکشن کے لیے شے قبول کرنے والے inject طریقوں کے ذریعے انجیکشن کے لیے کون سی اقسام دستیاب ہیں۔
// Module: وہ انحصاریاں فراہم کرتا ہے جو Dagger خود نہیں بنا سکتا
@Module
class NetworkModule {
@Provides
@Singleton
fun provideOkHttpClient(): OkHttpClient {
return OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.build()
}
@Provides
@Singleton
fun provideApiService(client: OkHttpClient): ApiService {
return Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiService::class.java)
}
}
// Component: Module اور Injection اہداف کو جوڑتا ہے
@Component(modules = [NetworkModule::class])
interface AppComponent {
fun inject(activity: MainActivity)
fun getApiService(): ApiService
}
@Module ایک کلاس ہے جس میں @Provides کے ساتھ طریقے ہوتے ہیں جو انحصار کی مثالیں واپس کرتے ہیں۔ Module ان اقسام کے لیے استعمال ہوتا ہے جو Dagger خود بخود نہیں بنا سکتا: فریق ثالث لائبریریاں (OkHttp، Retrofit)، کنسٹرکٹر پیرامیٹرز والی اشیاء، نفاذ کے انتخاب والے انٹرفیس۔ @Binds ان صورتوں میں @Provides کا متبادل ہے جب کوئی طریقہ انٹرفیس واپس کرتا ہے اور ایک واحد نفاذ قبول کرتا ہے: Dagger طریقہ کو بلائے بغیر براہ راست کاسٹ تیار کرتا ہے۔
@Scope انحصاری گراف میں کسی شے کی زندگی کا تعین کرتا ہے۔ @Singleton — شے پوری ایپلیکیشن کے لیے ایک بار بنائی جاتی ہے۔ @ActivityScoped — شے اس وقت تک زندہ رہتی ہے جب تک Activity زندہ ہے۔ @FragmentScoped — جب تک Fragment زندہ ہے۔ دائرہ کار کے بغیر، Dagger ہر انجیکشن پر ایک نیا نمونہ بناتا ہے۔ @Reusable — ان اشیاء کے لیے ایک دائرہ کار جو سنگلٹن ہونے کی ضرورت نہیں لیکن جن کی تخلیق مہنگی ہے — Dagger مثال کو کیش کر سکتا ہے لیکن اس کی ضمانت نہیں دیتا۔
Hilt پہلے سے طے شدہ اجزاء اور خودکار بنیادی گراف تخلیق کے ذریعے Android کے لیے Dagger کنفیگریشن کو آسان بناتی ہے۔ Application کلاس پر @HiltAndroidApp کا نشان Hilt جزو کی تخلیق کو متحرک کرتا ہے۔ اس نشان کے بغیر، Hilt کام نہیں کرتی — یہ Hilt استعمال کرنے والی کسی بھی Android ایپلیکیشن کے لیے لازمی ہے۔ @HiltAndroidApp والد SingletonComponent بناتا ہے، جس سے ایپلیکیشن کے دیگر تمام اجزاء وراثت پاتے ہیں۔
@HiltAndroidApp
class MyApplication : Application()
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject lateinit var apiService: ApiService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// apiService onCreate کال سے پہلے ہی انجیکٹ ہو چکا ہے
}
}
@Module
@InstallIn(SingletonComponent::class)
class AppModule {
@Provides
@Singleton
fun provideDatabase(@ApplicationContext ctx: Context): AppDatabase {
return Room.databaseBuilder(ctx, AppDatabase::class.java, "app.db").build()
}
}
@AndroidEntryPoint Activity، Fragment، Service، BroadcastReceiver اور View کے لیے ایک نشان ہے۔ یہ ہر قسم کے لیے Hilt جزو تیار کرتا ہے: Activity پر @AndroidEntryPoint ایک ActivityComponent بناتا ہے جو SingletonComponent سے وراثت پاتا ہے۔ ذیلی جزو خود بخود والد کی تمام انحصاریاں حاصل کرتا ہے۔ @Inject lateinit var کے ساتھ فیلڈ انجیکشن صرف @AndroidEntryPoint سے نشان زدہ کلاسز میں دستیاب ہے — عام کلاسز میں کنسٹرکٹر انجیکشن استعمال ہوتا ہے۔
@InstallIn بتاتا ہے کہ ماڈیول کس Hilt جزو میں نصب کیا گیا ہے۔ @InstallIn(SingletonComponent::class) کے ساتھ NetworkModule پوری ایپلیکیشن میں دستیاب ہے۔ @InstallIn(ActivityComponent::class) کے ساتھ Module صرف Activity میں دستیاب ہے۔ یہ انحصاری گراف کو الگ کرتا ہے: Activity کے مخصوص ماڈیول Fragment اور ViewModel میں نظر نہیں آتے، غلط انحصاریوں کے حادثاتی استعمال کو روکتے ہیں۔ @ApplicationContext ایپلیکیشن Context حاصل کرنے کے لیے Hilt کا بلٹ ان کوالیفائر ہے۔
جب ایک ہی انٹرفیس کے دو مختلف نفاذات کو انجیکٹ کرنے کی ضرورت ہو، تو کوالیفائر استعمال کیے جاتے ہیں۔ Hilt سٹرنگ شناخت کنندگان کے لیے @Named اور @Qualifier کے ساتھ حسب ضرورت نشانات کی حمایت کرتا ہے۔ مثال کے طور پر، مختلف سٹرنگ کنفیگریشنز کے لیے @Named("baseUrl") اور @Named("imageBaseUrl")۔ حسب ضرورت کوالیفائر مرتب وقت کی جانچ کی وجہ سے @Named پر ترجیح رکھتے ہیں — غلط سٹرنگ نام رن ٹائم تک دریافت نہیں ہوگا۔
@HiltViewModel ایک نشان ہے جو دستی ViewModelProvider.Factory کو تبدیل کرتا ہے۔ @HiltViewModel سے نشان زدہ اور @Inject constructor والی کلاس Dagger کے ذریعے خود بخود تمام انحصاریاں حاصل کرتی ہے۔ Hilt Jetpack ViewModelProvider کے ذریعہ استعمال کردہ ViewModelFactory تیار کرتی ہے۔ Hilt کے بغیر، ڈویلپر کو Activity یا Fragment سے ہر پیرامیٹر منتقل کرتے ہوئے دستی طور پر فیکٹری لکھنی پڑتی ہے۔
@HiltViewModel
class MainViewModel
@Inject constructor(
private val apiService: ApiService,
private val database: AppDatabase
) : ViewModel() {
private val _users = MutableStateFlow<List<User>>(emptyList())
val users: StateFlow<List<User>> = _users.asStateFlow()
fun loadUsers() {
viewModelScope.launch {
_users.value = apiService.getUsers()
}
}
}
// Activity میں — Hilt خود بخود ViewModel بناتا ہے
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
}
ViewModelScoped انحصار کے لیے Hilt کا ایک دائرہ کار ہے جو اس وقت تک زندہ رہتا ہے جب تک ViewModel زندہ ہے۔ اگر ایک ہی قسم کے دو ViewModel ایک ہی @ViewModelScoped انحصار کو انجیکٹ کرتے ہیں، تو ہر ایک اپنی مثال حاصل کرتا ہے۔ یہ @ViewModelScoped کو @ActivityScoped سے ممتاز کرتا ہے، جہاں ایک Activity تمام Fragment کے لیے ایک مثال حاصل کرتی ہے۔ ViewModel کے مخصوص انحصار (مثلاً SavedStateHandle) کے لیے، @HiltViewModel @Inject constructor(savedStateHandle: SavedStateHandle) کے ساتھ استعمال ہوتا ہے۔
Hilt Hilt Extensions لائبریری کے ذریعے معاون انجیکشن کی حمایت کرتی ہے۔ معاون انجیکشن انجیکشن کے وقت کنسٹرکٹر میں پیرامیٹرز منتقل کرنے کی اجازت دیتا ہے جب کچھ انحصاریاں صرف رن ٹائم پر معلوم ہوتی ہیں (مثلاً، ایک intent سے صارف ID)۔ معاون انجیکشن کے لیے @AssistedInject @Assisted پیرامیٹرز کے ساتھ استعمال ہوتا ہے۔ Hilt ایک AssistedFactory تیار کرتی ہے جسے معیاری طریقے سے انجیکٹ کیا جا سکتا ہے۔
خالص Dagger کے لیے Component کی دستی تخلیق، دائروں کی تعریف اور ہر Android جزو میں انجیکشن کنفیگریشن کی ضرورت ہوتی ہے۔ ڈویلپر AppComponent، ActivityComponent، FragmentComponent بناتا ہے اور @Subcomponent کے ذریعے ان کے تعلقات کا انتظام کرتا ہے۔ یہ طریقہ زیادہ سے زیادہ کنٹرول دیتا ہے لیکن اس کے لیے کافی بویلرپلیٹ کوڈ درکار ہے۔ Dagger بڑے پروجیکٹس میں استعمال ہوتا ہے جنہیں غیر معیاری DI فن تعمیر کی ضرورت ہوتی ہے، یا غیر Android Java/Kotlin پروجیکٹس میں۔
Hilt بویلرپلیٹ کو خودکار بناتی ہے: ایک @HiltAndroidApp، ہر جزو کے لیے ایک @AndroidEntryPoint، پہلے سے طے شدہ دائرے۔ Google تمام نئے Android پروجیکٹس کے لیے Hilt کی سفارش کرتا ہے۔ Dagger سے Hilt میں منتقلی میں Component کو @InstallIn سے تبدیل کرنا، @Subcomponent کو پہلے سے طے شدہ Hilt اجزاء سے تبدیل کرنا اور دستی ViewModelProvider.Factory کو @HiltViewModel سے تبدیل کرنا شامل ہے۔ زیادہ تر @Module کلاسیں @Provides طریقوں کو تبدیل کیے بغیر @InstallIn شامل کرکے منتقل کی جاتی ہیں۔
| خصوصیت | Dagger | Hilt |
|---|---|---|
| ترتیب | دستی: Component، Subcomponent، Builder | خودکار: @HiltAndroidApp، @AndroidEntryPoint |
| Android اجزاء | پہلے سے طے شدہ نہیں | 12+ بلٹ ان اجزاء |
| ViewModel | دستی فیکٹری | @HiltViewModel + @Inject constructor |
| ملٹی ماڈیول | @Component(dependencies) کے ذریعے | @InstallIn + جمع کے ذریعے |
| پیچیدگی | اعلی — تجربہ درکار | کم — بدیہی طور پر سمجھ میں آنے والا |
| لچک | زیادہ سے زیادہ | معیاری (95% منظرناموں کا احاطہ کرتا ہے) |
Hilt کی حدود: لائبریری صرف Android کو سپورٹ کرتی ہے (خالص سرور سائڈ Java پروجیکٹس کے لیے موزوں نہیں)، ایک مخصوص جزو ڈھانچہ نافذ کرتی ہے (اوور رائڈ کرنا مشکل)، اور Jetpack Compose پروجیکٹس کے لیے android.hilt:hilt-navigation-compose پر انحصار شامل کرتی ہے۔ Compose ایپلیکیشنز کے لیے، Hilt @HiltViewModel فراہم کرتی ہے جو Composable میں hiltViewModel() کے ذریعے قابل رسائی ہے — Activity سے دستی ViewModel فراہمی کے بغیر۔
اکثر پوچھے گئے سوالات
Dagger دستی Component اور Module کنفیگریشن کے ساتھ ایک بنیادی مرتب وقت DI فریم ورک ہے۔ Hilt ایک Android لفافہ ہے جو اجزاء کی تخلیق اور Activity، Fragment، ViewModel، Service اور BroadcastReceiver کے زندگی کے چکر کے ساتھ انضمام کو خودکار بناتا ہے۔
@HiltAndroidApp Application کے لیے Hilt جزو کی تخلیق کو فعال کرتا ہے۔ اس نشان کے بغیر، Hilt بنیادی SingletonComponent نہیں بنا سکتا جس سے تمام ActivityComponent، FragmentComponent اور ViewModelComponent وراثت پاتے ہیں۔ یہ نشان کسی بھی Hilt پروجیکٹ کے لیے لازمی ہے۔
Hilt Navigation NavBackStackEntry میں ViewModel کے لیے @HiltViewModel اور نیویگیشن گراف کے اندر ViewModel کو دائرہ کار میں لانے کے لیے hiltNavGraphViewModels() فراہم کرتی ہے۔ android.hilt:hilt-navigation-fragment لائبریری ہر NavBackStackEntry کے لیے خود بخود ایک ViewModel بناتی ہے۔
ایپلیکیشن Context کے لیے @ApplicationContext یا Activity Context کے لیے @ActivityContext استعمال کریں۔ Hilt یہ کوالیفائر android.hilt:hilt-android لائبریری میں بلٹ ان فراہم کرتا ہے۔ @ActivityContext صرف ActivityComponent میں نصب ماڈیولز میں دستیاب ہے۔
@Binds @Provides کا ایک موثر متبادل ہے جب کوئی طریقہ بالکل ایک پیرامیٹر قبول کرتا ہے اور اپنی قسم کو انٹرفیس کے طور پر واپس کرتا ہے۔ @Binds طریقہ کو بلائے بغیر براہ راست کاسٹ تیار کرتا ہے، تیار کردہ کوڈ کی مقدار کو کم کرتا ہے اور انجیکشن کی کارکردگی کو بہتر بناتا ہے۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں