ম্যানিফেস্ট ফাইল ম্যানেজ করুন

এই পৃষ্ঠায় ম্যানিফেস্ট মার্জিং কীভাবে কাজ করে এবং মার্জ সংক্রান্ত দ্বন্দ্বের সমাধান করতে আপনি কীভাবে মার্জ সংক্রান্ত পছন্দ প্রয়োগ করতে পারেন তা বর্ণনা করা হয়েছে। অ্যাপ ম্যানিফেস্ট ফাইলের ভূমিকা সম্পর্কে জানতে, অ্যাপ ম্যানিফেস্ট ওভারভিউ দেখুন।

একাধিক ম্যানিফেস্ট ফাইল মার্জ করুন

আপনার APK বা Android অ্যাপ বান্ডেল ফাইলে শুধু একটি AndroidManifest.xml ফাইল থাকতে পারে, তবে আপনার Android Studio প্রোজেক্টে প্রধান সোর্স সেট, বিল্ড ভেরিয়েন্ট ও ইমপোর্ট করা লাইব্রেরির মাধ্যমে প্রদান করা একাধিক ম্যানিফেস্ট ফাইল থাকতে পারে। আপনার অ্যাপ তৈরি করার সময়, Gradle বিল্ড সব ম্যানিফেস্ট ফাইলকে একক ম্যানিফেস্ট ফাইলে মার্জ করে যা আপনার অ্যাপে প্যাকেজ করা হয়।

ম্যানিফেস্ট মার্জার টুল প্রতিটি ফাইল থেকে সমস্ত XML এলিমেন্টকে একত্রিত করে মার্জ হিউরিস্টিকস অনুসরণ করে এবং আপনার দ্বারা সংজ্ঞায়িত মার্জ পছন্দগুলি মেনে চলে বিশেষ XML অ্যাট্রিবিউট সহ।

পরামর্শ: মার্জ করা ম্যানিফেস্টের ফলাফল প্রিভিউ করতে এবং কনফ্লিক্ট সংক্রান্ত সমস্যা খুঁজতে, নিম্নলিখিত বিভাগে বর্ণনা করা মার্জ করা ম্যানিফেস্ট ভিউ ব্যবহার করুন।

অগ্রাধিকার মার্জ করুন

মার্জার টুল প্রতিটি ম্যানিফেস্ট ফাইলের অগ্রাধিকারের ভিত্তিতে, সব ম্যানিফেস্ট ফাইলকে ক্রমানুসারে একটি ফাইলে একত্রিত করে। যেমন, আপনার কাছে তিনটি ম্যানিফেস্ট ফাইল থাকলে, সবচেয়ে কম অগ্রাধিকারের ম্যানিফেস্টটি পরবর্তী-সর্বোচ্চ-অগ্রাধিকারের ম্যানিফেস্টে মার্জ করা হয় এবং তারপরে সেটি সর্বোচ্চ-অগ্রাধিকারের ম্যানিফেস্টে মার্জ করা হয়, যেমনটি চিত্র ১-এ দেখানো হয়েছে।

ছবি ১. তিনটি ম্যানিফেস্ট ফাইল মার্জ করার প্রসেস, সবচেয়ে কম অগ্রাধিকার থেকে সবচেয়ে বেশি অগ্রাধিকার।

তিনটি প্রাথমিক ধরনের ম্যানিফেস্ট ফাইল আছে যেগুলি একে অপরের সাথে মার্জ করা হতে পারে এবং তাদের মার্জ করার অগ্রাধিকার নিচে দেওয়া হল (সবচেয়ে বেশি অগ্রাধিকার প্রথমে):

  1. আপনার বিল্ড ভেরিয়েন্ট-এর জন্য ম্যানিফেস্ট ফাইল

    আপনার ভেরিয়েন্টের জন্য একাধিক সোর্স সেট থাকলে, সেগুলির ম্যানিফেস্টের অগ্রাধিকার নিচে উল্লেখ করা হল:

    • বিল্ড ভেরিয়েন্ট ম্যানিফেস্ট (যেমন src/demoDebug/)
    • বিল্ড টাইপ ম্যানিফেস্ট (যেমন src/debug/)
    • প্রোডাক্ট ফ্লেভার ম্যানিফেস্ট (যেমন src/demo/)

      আপনি ফ্লেভার ডাইমেনশন ব্যবহার করলে, ম্যানিফেস্টের অগ্রাধিকার flavorDimensions প্রপার্টিতে প্রতিটি ডাইমেনশন যে ক্রমে তালিকাভুক্ত করা হয়েছে তার সাথে মিলে যায় (প্রথমটি হল সর্বোচ্চ অগ্রাধিকার)।

  2. অ্যাপ মডিউলের জন্য মূল ম্যানিফেস্ট ফাইল
  3. অন্তর্ভুক্ত লাইব্রেরি থেকে ম্যানিফেস্ট ফাইল

    আপনার একাধিক লাইব্রেরি থাকলে, তাদের ম্যানিফেস্টের অগ্রাধিকার আপনার Gradle dependencies ব্লকে যে ক্রমে দেখানো হয় তার সাথে মিলে যায়।

যেমন, লাইব্রেরি ম্যানিফেস্ট মূল ম্যানিফেস্টে মার্জ করা হয়, তারপর মূল ম্যানিফেস্ট বিল্ড ভেরিয়েন্ট ম্যানিফেস্টে মার্জ করা হয়। মনে রাখবেন, এগুলি হল সব সোর্স সেটের জন্য একই মার্জ করার অগ্রাধিকার, যেমনটি সোর্স সেট সহ তৈরি করুন-এ বর্ণনা করা হয়েছে।

গুরুত্বপূর্ণ: build.gradle ফাইল থেকে বিল্ড কনফিগারেশন মার্জ করা ম্যানিফেস্ট ফাইলের যেকোনও সংশ্লিষ্ট অ্যাট্রিবিউট ওভাররাইড করে। যেমন, build.gradle বা build.gradle.kts ফাইল থেকে minSdk, <uses-sdk> ম্যানিফেস্ট এলিমেন্টে ম্যাচিং অ্যাট্রিবিউট ওভাররাইড করে। বিভ্রান্তি এড়াতে, <uses-sdk> এলিমেন্ট বাদ দিন এবং শুধুমাত্র build.gradle ফাইলে এইসব প্রপার্টি উল্লেখ করুন। আরও বিবরণের জন্য, আপনার বিল্ড কনফিগার করুন দেখুন।

মার্জ কনফ্লিক্ট হিউরিস্টিকস

মার্জার টুল, একটি ম্যানিফেস্টের প্রতিটি XML এলিমেন্টকে অন্য ম্যানিফেস্টের সংশ্লিষ্ট এলিমেন্টের সাথে যৌক্তিকভাবে মেলাতে পারে। ম্যাচিং কীভাবে কাজ করে সেই সম্পর্কে বিস্তারিত জানতে, আগের বিভাগে মার্জ করার অগ্রাধিকার দেখুন।

কম-অগ্রাধিকারের ম্যানিফেস্টের কোনও এলিমেন্ট যদি বেশি-অগ্রাধিকারের ম্যানিফেস্টের কোনও এলিমেন্টের সাথে না মেলে, তাহলে সেটি মার্জ করা ম্যানিফেস্টে যোগ করা হয়। তবে, যদি কোনও ম্যাচিং এলিমেন্ট থাকে, তাহলে মার্জার টুল প্রতিটি থেকে সমস্ত অ্যাট্রিবিউট একই এলিমেন্টে একত্রিত করার চেষ্টা করে। টুলটি যদি দেখে যে দুটি ম্যানিফেস্টে আলাদা আলাদা ভ্যালু সহ একই অ্যাট্রিবিউট আছে, তাহলে মার্জ করার সময় সমস্যা হয়।

মার্জার টুল একই এলিমেন্টে সব অ্যাট্রিবিউট কম্বাইন করার চেষ্টা করলে কী কী ফলাফল হতে পারে তা সারণী ১-এ দেখানো হয়েছে।

টেবিল ১. অ্যাট্রিবিউট ভ্যালুর জন্য ডিফল্ট মার্জ আচরণ

বেশি গুরুত্বপূর্ণ অ্যাট্রিবিউট কম-অগ্রাধিকার অ্যাট্রিবিউট অ্যাট্রিবিউটের মার্জ করা ফলাফল
কোনও মূল্যই নেই কোনও মূল্যই নেই কোনও ভ্যালু নেই (ডিফল্ট ভ্যালু ব্যবহার করুন)
ভ্যালু খ ভ্যালু খ
ভ্যালু ক কোনও মূল্যই নেই ভ্যালু ক
ভ্যালু ক ভ্যালু ক
ভ্যালু খ কনফ্লিক্ট সংক্রান্ত সমস্যা—আপনাকে অবশ্যই একটি মার্জ করার নিয়ম সংক্রান্ত মার্কার যোগ করতে হবে।

তবে, মার্জ করার সময় হওয়া সমস্যা এড়াতে মার্জার টুল কিছু পরিস্থিতিতে আলাদাভাবে কাজ করে:

  • <manifest> এলিমেন্টের অ্যাট্রিবিউট কখনও একসাথে মার্জ করা হয় না; শুধুমাত্র সর্বোচ্চ-অগ্রাধিকার ম্যানিফেস্টের অ্যাট্রিবিউট ব্যবহার করা হয়।
  • android:required অ্যাট্রিবিউট <uses-feature> এবং <uses-library> এলিমেন্টে OR মার্জ ব্যবহার করে। কোনও দ্বন্দ্ব থাকলে, "true" প্রয়োগ করা হয় এবং একটি ম্যানিফেস্টের জন্য প্রয়োজনীয় ফিচার বা লাইব্রেরি সবসময় অন্তর্ভুক্ত করা হয়।
  • <uses-sdk> এলিমেন্টের অ্যাট্রিবিউট সবসময় বেশি-অগ্রাধিকারের ম্যানিফেস্ট থেকে ভ্যালু ব্যবহার করে, তবে নিম্নলিখিত পরিস্থিতিতে তা করে না:
    • কম-অগ্রাধিকারের ম্যানিফেস্টে minSdk ভ্যালু থাকলে যা বেশি, আপনি overrideLibrary মার্জ করার নিয়ম প্রয়োগ না করা পর্যন্ত একটি সমস্যা হয়।
    • কম-অগ্রাধিকার ম্যানিফেস্টে targetSdkVersion ভ্যালু কম থাকলে, মার্জার টুল বেশি-অগ্রাধিকার ম্যানিফেস্টের ভ্যালু ব্যবহার করে এবং ইম্পোর্ট করা লাইব্রেরি যাতে সঠিকভাবে কাজ করা চালিয়ে যেতে পারে তা নিশ্চিত করার জন্য প্রয়োজনীয় যেকোনও সিস্টেম অনুমতিও যোগ করে (যেসব ক্ষেত্রে Android-এর নতুন ভার্সনে অনুমতি সংক্রান্ত বিধিনিষেধ বাড়ানো হয়েছে)। এই ধরনের আচরণ সম্পর্কে আরও জানতে, সিস্টেমের অন্তর্নিহিত অনুমতি সংক্রান্ত বিভাগটি দেখুন।
  • ম্যানিফেস্টের মধ্যে <intent-filter> এলিমেন্ট কখনও ম্যাচ করে না। প্রতিটি অনন্য হিসেবে বিবেচিত হয় এবং মার্জ করা ম্যানিফেস্টে সাধারণ পেরেন্ট এলিমেন্টে যোগ করা হয়।

অ্যাট্রিবিউটের মধ্যে অন্যান্য সব বিরোধের জন্য, আপনি একটি ত্রুটি পাবেন এবং আপনাকে অবশ্যই মার্জার টুলকে নির্দেশ দিতে হবে যে কীভাবে উচ্চ-অগ্রাধিকার ম্যানিফেস্ট ফাইলে একটি বিশেষ অ্যাট্রিবিউট যোগ করে এটি সমাধান করা যায়। মার্জ রুল মার্কার সম্পর্কে নিম্নলিখিত বিভাগ দেখুন।

ডিফল্ট অ্যাট্রিবিউট ভ্যালুর উপর নির্ভর করবেন না। কারণ সব অনন্য অ্যাট্রিবিউট একই এলিমেন্টে একত্রিত করা হয়, এর ফলে অপ্রত্যাশিত ফলাফল হতে পারে যদি উচ্চ-অগ্রাধিকার ম্যানিফেস্ট আসলে কোনও অ্যাট্রিবিউটের ডিফল্ট ভ্যালুর উপর নির্ভর করে, সেটি ঘোষণা না করেই। যেমন, বেশি- অগ্রাধিকারের ম্যানিফেস্ট যদি android:launchMode অ্যাট্রিবিউট ঘোষণা না করে, তাহলে এটি "standard"-এর ডিফল্ট ভ্যালু ব্যবহার করে—কিন্তু কম-অগ্রাধিকারের ম্যানিফেস্ট যদি অন্য ভ্যালু সহ এই অ্যাট্রিবিউট ঘোষণা করে, তাহলে সেই ভ্যালু মার্জ করা ম্যানিফেস্টে প্রয়োগ করা হয়, যা ডিফল্ট ভ্যালুকে ওভাররাইড করে। আপনি যেমন চান, প্রতিটি অ্যাট্রিবিউটকে ঠিক সেইভাবে স্পষ্টভাবে সংজ্ঞায়িত করতে হবে। প্রতিটি অ্যাট্রিবিউটের জন্য ডিফল্ট ভ্যালু ম্যানিফেস্ট রেফারেন্স-এ ডকুমেন্ট করা আছে।

নিয়ম মার্কার মার্জ করুন

মার্জ রুল মার্কার হল একটি XML অ্যাট্রিবিউট যা আপনি মার্জ সংক্রান্ত দ্বন্দ্ব সমাধান করা বা অবাঞ্ছিত এলিমেন্ট ও অ্যাট্রিবিউট সরিয়ে দেওয়ার ব্যাপারে আপনার পছন্দ প্রকাশ করতে ব্যবহার করতে পারেন। আপনি সম্পূর্ণ এলিমেন্ট অথবা এলিমেন্টের নির্দিষ্ট অ্যাট্রিবিউটে মার্কার প্রয়োগ করতে পারবেন।

দুটি ম্যানিফেস্ট ফাইল মার্জ করার সময়, মার্জার টুল বেশি-অগ্রাধিকারের ম্যানিফেস্ট ফাইলে এই মার্কারগুলি খোঁজে।

সব মার্কার Android tools নেমস্পেসের অন্তর্গত, তাই আপনাকে প্রথমে <manifest> এলিমেন্টে এই নেমস্পেস ঘোষণা করতে হবে, যেমন এখানে দেখানো হয়েছে:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp"
    xmlns:tools="http://schemas.android.com/tools">

Node মার্কার

কোনও মার্জ রুল সম্পূর্ণ XML এলিমেন্টে (প্রদত্ত ম্যানিফেস্ট এলিমেন্টের সব অ্যাট্রিবিউট এবং এর সব চাইল্ড ট্যাগে) প্রয়োগ করতে, নিম্নলিখিত অ্যাট্রিবিউট ব্যবহার করুন:

tools:node="merge"
এই ট্যাগ এবং সব নেস্টেড এলিমেন্টের সব অ্যাট্রিবিউট মার্জ করুন, যখন মার্জ কনফ্লিক্ট হিউরিস্টিক ব্যবহার করে কোনও কনফ্লিক্ট হয় না। এটি হল এলিমেন্টের জন্য ডিফল্ট অ্যাকশন।

কম-অগ্রাধিকারের ম্যানিফেস্ট:

<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

বেশি অগ্রাধিকারযুক্ত ম্যানিফেস্ট:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:node="merge">
</activity>

মার্জ করা ম্যানিফেস্ট ফলাফল:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
tools:node="mergeOnlyAttributes"
শুধু এই ট্যাগে অ্যাট্রিবিউট মার্জ করুন; নেস্টেড এলিমেন্ট মার্জ করবেন না।

কম-অগ্রাধিকারের ম্যানিফেস্ট:

<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <data android:type="image/*" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

বেশি অগ্রাধিকারযুক্ত ম্যানিফেস্ট:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:node="mergeOnlyAttributes">
</activity>

মার্জ করা ম্যানিফেস্ট ফলাফল:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">
</activity>
tools:node="remove"
মার্জ করা ম্যানিফেস্ট থেকে এই এলিমেন্ট সরিয়ে দিন। মার্জ করা ম্যানিফেস্টে এমন কোনও এলিমেন্ট খুঁজে পেলে এটি ব্যবহার করা হয় যা আপনার প্রয়োজন নেই এবং যা কম-অগ্রাধিকারের ম্যানিফেস্ট ফাইল থেকে পাওয়া গেছে এবং যা আপনার নিয়ন্ত্রণে নেই (যেমন, ইমপোর্ট করা লাইব্রেরি)।

কম-অগ্রাধিকারের ম্যানিফেস্ট:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="cow"
      android:value="@string/moo"/>
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>

বেশি অগ্রাধিকারযুক্ত ম্যানিফেস্ট:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="cow"
      tools:node="remove"/>
</activity-alias>

মার্জ করা ম্যানিফেস্ট ফলাফল:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>
tools:node="removeAll"
tools:node="remove"-এর মতো, তবে এটি এই এলিমেন্টের ধরনের সাথে (একই পেরেন্ট এলিমেন্টের মধ্যে) মিলে যাওয়া সব এলিমেন্ট সরিয়ে দেয়।

কম-অগ্রাধিকারের ম্যানিফেস্ট:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="cow"
      android:value="@string/moo"/>
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>

বেশি অগ্রাধিকারযুক্ত ম্যানিফেস্ট:

<activity-alias android:name="com.example.alias">
  <meta-data tools:node="removeAll"/>
</activity-alias>

মার্জ করা ম্যানিফেস্ট ফলাফল:

<activity-alias android:name="com.example.alias">
</activity-alias>
tools:node="replace"
কম-অগ্রাধিকারের এলিমেন্ট সম্পূর্ণভাবে পরিবর্তন করুন। অর্থাৎ, কম-অগ্রাধিকারের ম্যানিফেস্টে যদি কোনও মিলে যাওয়া এলিমেন্ট থাকে, তাহলে সেটি উপেক্ষা করুন এবং এই ম্যানিফেস্টে যেভাবে দেখানো হয়েছে ঠিক সেভাবেই এই এলিমেন্ট ব্যবহার করুন।

কম-অগ্রাধিকারের ম্যানিফেস্ট:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="cow"
      android:value="@string/moo"/>
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>

বেশি অগ্রাধিকারযুক্ত ম্যানিফেস্ট:

<activity-alias android:name="com.example.alias"
    tools:node="replace">
  <meta-data android:name="fox"
      android:value="@string/dingeringeding"/>
</activity-alias>

মার্জ করা ম্যানিফেস্ট ফলাফল:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="fox"
      android:value="@string/dingeringeding"/>
</activity-alias>
tools:node="strict"
কম-অগ্রাধিকারের ম্যানিফেস্টে এই এলিমেন্টটি বেশি-অগ্রাধিকারের ম্যানিফেস্টের এলিমেন্টের সাথে হুবহু না মিললে যেকোনও সময় বিল্ড ফেলিওর জেনারেট করুন (অন্য মার্জ রুল মার্কারের মাধ্যমে সমাধান না করা হলে)। এটি মার্জ কনফ্লিক্ট হিউরিস্টিক ওভাররাইড করে। যেমন, কম-অগ্রাধিকারের ম্যানিফেস্টে অতিরিক্ত অ্যাট্রিবিউট থাকলে, বিল্ড ব্যর্থ হয় (যদিও ডিফল্ট অ্যাকশন মার্জ করা ম্যানিফেস্টে অতিরিক্ত অ্যাট্রিবিউট যোগ করে)।

কম-অগ্রাধিকারের ম্যানিফেস্ট:

<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

বেশি অগ্রাধিকারযুক্ত ম্যানিফেস্ট:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:node="strict">
</activity>

এর ফলে ম্যানিফেস্ট মার্জ সংক্রান্ত সমস্যা হয়। স্ট্রিক্ট মোডে দুটি ম্যানিফেস্ট এলিমেন্ট একে অপরের থেকে আলাদা হতে পারে না। এই পার্থক্যগুলি সমাধান করতে আপনাকে অবশ্যই অন্যান্য মার্জ রুল মার্কার প্রয়োগ করতে হবে। (tools:node="strict" ছাড়া, এই দুটি ফাইল কোনও সমস্যা ছাড়াই একসাথে মার্জ করা যেতে পারে, যেমন tools:node="merge"-এর উদাহরণে দেখানো হয়েছে।)

অ্যাট্রিবিউট মার্কার

পরিবর্তে, ম্যানিফেস্ট ট্যাগের শুধুমাত্র নির্দিষ্ট অ্যাট্রিবিউটে মার্জ করার নিয়ম প্রয়োগ করতে, নিম্নলিখিত অ্যাট্রিবিউটগুলি ব্যবহার করুন। প্রতিটি অ্যাট্রিবিউট এক বা একাধিক অ্যাট্রিবিউটের নাম (অ্যাট্রিবিউট নেমস্পেস সহ) গ্রহণ করে, যা কমা দিয়ে আলাদা করা থাকে।

tools:remove="attr, ..."
মার্জ করা ম্যানিফেস্ট থেকে নির্দিষ্ট অ্যাট্রিবিউট সরিয়ে দিন। কম-অগ্রাধিকারের ম্যানিফেস্ট ফাইলে এইসব অ্যাট্রিবিউট অন্তর্ভুক্ত থাকলে এবং আপনি মার্জ করা ম্যানিফেস্টে সেগুলি অন্তর্ভুক্ত করতে না চাইলে এটি ব্যবহার করা হয়।

কম-অগ্রাধিকারের ম্যানিফেস্ট:

<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">

বেশি অগ্রাধিকারযুক্ত ম্যানিফেস্ট:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:remove="android:windowSoftInputMode">

মার্জ করা ম্যানিফেস্ট ফলাফল:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait">
tools:replace="attr, ..."
কম-অগ্রাধিকারের ম্যানিফেস্টে নির্দিষ্ট অ্যাট্রিবিউটগুলি এই ম্যানিফেস্টের অ্যাট্রিবিউট দিয়ে পরিবর্তন করুন। অন্যভাবে বলতে গেলে, বেশি অগ্রাধিকারের ম্যানিফেস্টের ভ্যালু সবসময় রেখে দিন।

কম-অগ্রাধিকারের ম্যানিফেস্ট:

<activity android:name="com.example.ActivityOne"
    android:theme="@oldtheme"
    android:exported="false"
    android:windowSoftInputMode="stateUnchanged">

বেশি অগ্রাধিকারযুক্ত ম্যানিফেস্ট:

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:screenOrientation="portrait"
    tools:replace="android:theme,android:exported">

মার্জ করা ম্যানিফেস্ট ফলাফল:

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">
tools:strict="attr, ..."
কম-অগ্রাধিকার ম্যানিফেস্টে এইসব অ্যাট্রিবিউট বেশি-অগ্রাধিকার ম্যানিফেস্টের অ্যাট্রিবিউটের সাথে সম্পূর্ণভাবে ম্যাচ না করলে, যেকোনও সময় বিল্ড ফেলিওর জেনারেট করুন। মার্জ কনফ্লিক্ট হিউরিস্টিক-এ বর্ণিত বিশেষ আচরণ সহ অ্যাট্রিবিউটগুলি ছাড়া অন্য সব অ্যাট্রিবিউটের জন্য এটি ডিফল্ট আচরণ।

কম-অগ্রাধিকারের ম্যানিফেস্ট:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="landscape">
</activity>

বেশি অগ্রাধিকারযুক্ত ম্যানিফেস্ট:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:strict="android:screenOrientation">
</activity>

এর ফলে ম্যানিফেস্ট মার্জ সংক্রান্ত সমস্যা হয়। সমস্যা সমাধান করতে আপনাকে অবশ্যই অন্য মার্জ রুল মার্কার প্রয়োগ করতে হবে। এটি হল ডিফল্ট অ্যাকশন, তাই tools:strict="screenOrientation" স্পষ্টভাবে যোগ করার ক্ষেত্রেও একই ফলাফল পাওয়া যায়।

এছাড়াও, আপনি একটি এলিমেন্টে একাধিক মার্কার প্রয়োগ করতে পারবেন, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

কম-অগ্রাধিকারের ম্যানিফেস্ট:

<activity android:name="com.example.ActivityOne"
    android:theme="@oldtheme"
    android:exported="false"
    android:allowTaskReparenting="true"
    android:windowSoftInputMode="stateUnchanged">

বেশি অগ্রাধিকারযুক্ত ম্যানিফেস্ট:

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:screenOrientation="portrait"
    tools:replace="android:theme,android:exported"
    tools:remove="android:windowSoftInputMode">

মার্জ করা ম্যানিফেস্ট ফলাফল:

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:allowTaskReparenting="true"
    android:screenOrientation="portrait">

মার্কার বাছাইকারী

আপনি যদি শুধুমাত্র একটি নির্দিষ্ট ইম্পোর্ট করা লাইব্রেরিতে মার্জ রুল মার্কার প্রয়োগ করতে চান, তাহলে লাইব্রেরি প্যাকেজের নামের সাথে tools:selector অ্যাট্রিবিউট যোগ করুন।

যেমন, নিম্নলিখিত ম্যানিফেস্টের ক্ষেত্রে, remove মার্জ করার নিয়ম তখনই প্রযোজ্য হয় যখন কম-অগ্রাধিকারের ম্যানিফেস্ট ফাইলটি com.example.lib1 লাইব্রেরি থেকে আসে:

<permission android:name="permissionOne"
    tools:node="remove"
    tools:selector="com.example.lib1">

কম-অগ্রাধিকারের ম্যানিফেস্ট অন্য কোনও সোর্স থেকে হলে, remove মার্জ করার নিয়ম উপেক্ষা করা হয়।

মনে রাখবেন: আপনি যদি এটি কোনও একটি অ্যাট্রিবিউট মার্কারের সাথে ব্যবহার করেন, তাহলে এটি মার্কারের মধ্যে নির্দিষ্ট করা সব অ্যাট্রিবিউটের ক্ষেত্রে প্রযোজ্য হবে।

ইমপোর্ট করা লাইব্রেরির জন্য <uses-sdk> ওভাররাইড করুন

ডিফল্ট হিসেবে, মূল ম্যানিফেস্ট ফাইলের চেয়ে বেশি minSdk ভ্যালু আছে এমন লাইব্রেরি ইমপোর্ট করার সময় সমস্যা হয় এবং লাইব্রেরি ইমপোর্ট করা যায় না।

মার্জার টুল যাতে এই দ্বন্দ্ব উপেক্ষা করে এবং আপনার অ্যাপের কম minSdk মান রেখে লাইব্রেরি ইমপোর্ট করে, তার জন্য <uses-sdk> ট্যাগে overrideLibrary অ্যাট্রিবিউট যোগ করুন। অ্যাট্রিবিউট ভ্যালু এক বা একাধিক লাইব্রেরি প্যাকেজের নাম হতে পারে (কমা দিয়ে আলাদা করা), যা প্রধান ম্যানিফেস্টের minSdk ওভাররাইড করতে পারে এমন লাইব্রেরি নির্দেশ করে।

যেমন, আপনার অ্যাপের প্রধান ম্যানিফেস্ট যদি overrideLibrary এইভাবে প্রয়োগ করে:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.app"
          xmlns:tools="http://schemas.android.com/tools">
  <uses-sdk tools:overrideLibrary="com.example.lib1, com.example.lib2"/>
...

তাহলে, <uses-sdk> ট্যাগ সংক্রান্ত কোনও সমস্যা ছাড়াই নিম্নলিখিত ম্যানিফেস্ট মার্জ করা যাবে এবং মার্জ করা ম্যানিফেস্টে অ্যাপ ম্যানিফেস্ট থেকে minSdk="2" রাখা হবে।

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.lib1">
   <uses-sdk android:minSdk="4" />
...

অন্তর্নিহিত সিস্টেমের অনুমতি

কিছু Android API যা একসময় অ্যাপের মাধ্যমে ফ্রিতে অ্যাক্সেস করা যেত, সেগুলি Android-এর সাম্প্রতিক ভার্সনে সিস্টেম অনুমতি দ্বারা সীমাবদ্ধ করা হয়েছে।

যেসব অ্যাপ এইসব API অ্যাক্সেস করতে চায়, সেগুলি যাতে কাজ করা বন্ধ না করে দেয়, তার জন্য Android-এর সাম্প্রতিক ভার্সন, অ্যাপকে অনুমতি ছাড়াই সেইসব API অ্যাক্সেস করা চালিয়ে যেতে দেয়, যদি targetSdkVersion-এর ভ্যালু, যে ভার্সনে বিধিনিষেধ যোগ করা হয়েছে তার থেকে কম সেট করা থাকে। এই আচরণ অ্যাপটিকে API-তে অ্যাক্সেসের অনুমতি দেওয়ার জন্য একটি অন্তর্নিহিত অনুমতি দেয়। মার্জ করা ম্যানিফেস্ট যার targetSdkVersion-এর জন্য আলাদা আলাদা ভ্যালু আছে, তা প্রভাবিত হতে পারে।

কম-অগ্রাধিকারের ম্যানিফেস্ট ফাইলে targetSdkVersion-এর জন্য কম ভ্যালু থাকলে, যা এটিকে একটি অন্তর্নিহিত অনুমতি প্রদান করে, এবং বেশি-অগ্রাধিকারের ম্যানিফেস্টে একই অন্তর্নিহিত অনুমতি না থাকলে (কারণ এর targetSdkVersion যে ভার্সনে বিধিনিষেধ যোগ করা হয়েছে তার সমান বা তার বেশি), তাহলে মার্জার টুল মার্জ করা ম্যানিফেস্টে স্পষ্টভাবে সিস্টেম অনুমতি যোগ করে।

যেমন, আপনার অ্যাপ যদি targetSdkVersion-কে ৪ বা তার বেশি হিসেবে সেট করে এবং targetSdkVersion-কে ৩ বা তার কম হিসেবে সেট করে কোনও লাইব্রেরি ইমপোর্ট করে, তাহলে মার্জার টুল মার্জ করা ম্যানিফেস্টে WRITE_EXTERNAL_STORAGE অনুমতি যোগ করে।

সারণী ২-এ সম্ভাব্য সব অনুমতির তালিকা দেওয়া আছে যা আপনার মার্জ করা ম্যানিফেস্টে যোগ করা যেতে পারে:

সারণী ২. মার্জার টুল মার্জ করা ম্যানিফেস্টে যেসব অনুমতি যোগ করতে পারে তার তালিকা

কম-অগ্রাধিকার ম্যানিফেস্ট ঘোষণা করে মার্জ করা ম্যানিফেস্টে অনুমতি যোগ করা হয়েছে
targetSdkVersion ৩ বা তার কম WRITE_EXTERNAL_STORAGE, READ_PHONE_STATE
targetSdkVersion-এর বয়স ১৫ বা তার কম এবং READ_CONTACTS ব্যবহার করছে READ_CALL_LOG
targetSdkVersion-এর বয়স ১৫ বা তার কম এবং WRITE_CONTACTS ব্যবহার করছে WRITE_CALL_LOG

মার্জ করা ম্যানিফেস্ট পরীক্ষা করে দেখুন এবং কনফ্লিক্ট খুঁজে বের করুন

এমনকি আপনার অ্যাপ তৈরি করার আগেই, আপনার মার্জ করা ম্যানিফেস্ট কেমন দেখতে লাগে তার প্রিভিউ দেখতে পারবেন। প্রিভিউ দেখতে, নিম্নলিখিত ধাপগুলি অনুসরণ করুন:

  1. Android Studio-তে আপনার AndroidManifest.xml ফাইল খুলুন।
  2. এডিটরের নিচে মার্জ করা ম্যানিফেস্ট ট্যাবে ক্লিক করুন।

মার্জ করা ম্যানিফেস্ট ভিউতে বাঁদিকে মার্জ করা ম্যানিফেস্টের ফলাফল এবং ডানদিকে প্রতিটি মার্জ করা ম্যানিফেস্ট ফাইলের তথ্য দেখানো হয়, যেমনটি ছবি ২-এ দেখানো হয়েছে।

কম-অগ্রাধিকারের ম্যানিফেস্ট ফাইল থেকে মার্জ করা এলিমেন্টগুলি বাঁদিকে বিভিন্ন রঙে হাইলাইট করা হয়েছে। প্রতিটি রঙের জন্য কী ম্যানিফেস্ট সোর্স-এর অধীনে উল্লেখ করা আছে।

ছবি ২. মার্জ করা ম্যানিফেস্ট ভিউ।

বিল্ডের অংশ ছিল কিন্তু এলিমেন্ট বা অ্যাট্রিবিউট কন্ট্রিবিউট করেনি এমন ম্যানিফেস্ট ফাইলগুলি অন্যান্য ম্যানিফেস্ট ফাইল-এর অধীনে তালিকাভুক্ত করা হয়েছে।

কোনও এলিমেন্ট কোথা থেকে এসেছে সেই সম্পর্কে তথ্য দেখতে, বাঁদিকের প্যানেলে সেটিতে ক্লিক করুন এবং মার্জিং লগ-এর অধীনে বিবরণ দেখতে পাবেন।

কোনও দ্বন্দ্ব দেখা দিলে, সেটি মার্জ করার সময় হওয়া সমস্যা বিভাগে দেখানো হয় এবং মার্জ করার নিয়ম সংক্রান্ত মার্কার ব্যবহার করে কীভাবে দ্বন্দ্বের সমাধান করা যায় সেই বিষয়ে সাজেশন দেওয়া হয়।

এছাড়াও, ইভেন্ট লগ উইন্ডোতে সমস্যাগুলি প্রিন্ট করা হয়। সেগুলি দেখতে, ভিউ > টুল উইন্ডো > ইভেন্ট লগ বিকল্প বেছে নিন।

মার্জিং ডিসিশন ট্রির সম্পূর্ণ লগ দেখতে, আপনি আপনার মডিউলের build/outputs/logs/ ডিরেক্টরিতে লগ ফাইল খুঁজে পেতে পারেন, যার নাম manifest-merger-buildVariant-report.txt।

মার্জ করার নীতি

ম্যানিফেস্ট মার্জার টুল, একটি ম্যানিফেস্ট ফাইলের প্রতিটি XML এলিমেন্টকে অন্য ফাইলের সংশ্লিষ্ট এলিমেন্টের সাথে যৌক্তিকভাবে ম্যাচ করতে পারে। মার্জার ম্যাচ কী ব্যবহার করে প্রতিটি এলিমেন্ট ম্যাচ করে, এটি হয় একটি অনন্য অ্যাট্রিবিউট ভ্যালু (যেমন android:name) অথবা ট্যাগের নিজস্ব স্বাভাবিক অনন্যতা (যেমন, শুধুমাত্র একটি <supports-screen> এলিমেন্ট থাকতে পারে)।

দুটি ম্যানিফেস্টে একই XML এলিমেন্ট থাকলে, টুলটি তিনটি মার্জ নীতির মধ্যে একটি ব্যবহার করে দুটি এলিমেন্ট একসাথে মার্জ করে:

মার্জ করুন
সব নন-কনফ্লিক্টিং অ্যাট্রিবিউট একই ট্যাগে একত্রিত করুন এবং চাইল্ড এলিমেন্টকে তাদের নিজ নিজ মার্জিং নীতি অনুযায়ী মার্জ করুন। কোনও অ্যাট্রিবিউট একে অপরের সাথে বিরোধ করলে, মার্জ করার নিয়ম মার্কার ব্যবহার করে সেগুলি একসাথে মার্জ করুন।
শুধুমাত্র চিল্ড্রেন আইটেম মার্জ করুন
অ্যাট্রিবিউট একত্রিত বা মার্জ করবেন না (শুধুমাত্র সর্বোচ্চ-অগ্রাধিকার ম্যানিফেস্ট ফাইল দ্বারা প্রদত্ত অ্যাট্রিবিউট রাখুন) এবং মার্জিং নীতি অনুযায়ী চাইল্ড এলিমেন্ট মার্জ করুন।
Keep
এলিমেন্টটি যেমন আছে তেমন রেখে দিন এবং মার্জ করা ফাইলের সাধারণ পেরেন্ট এলিমেন্টে এটি যোগ করুন। একই এলিমেন্টের একাধিক ঘোষণা গ্রহণযোগ্য হলে তবেই এটি ব্যবহার করা হয়।

সারণী ৩-এ প্রতিটি এলিমেন্টের ধরন, ব্যবহৃত মার্জ নীতির ধরন এবং দুটি ম্যানিফেস্টের মধ্যে এলিমেন্ট ম্যাচ নির্ধারণ করতে ব্যবহৃত কী তালিকাভুক্ত করা হয়েছে:

সারণী ৩. ম্যানিফেস্ট এলিমেন্ট মার্জ করার নীতি এবং ম্যাচ কী

এলিমেন্ট মার্জ নীতি ম্যাচ কী
<action> মার্জ করুন android:name অ্যাট্রিবিউট
<activity> মার্জ করুন android:name অ্যাট্রিবিউট
<application> মার্জ করুন প্রতি <manifest>-এ শুধুমাত্র একটিই আছে।
<category> মার্জ করুন android:name অ্যাট্রিবিউট
<data> মার্জ করুন প্রতি <intent-filter>-এ শুধুমাত্র একটিই আছে।
<grant-uri-permission> মার্জ করুন প্রতি <provider>-এ শুধুমাত্র একটিই আছে।
<instrumentation> মার্জ করুন android:name অ্যাট্রিবিউট
<intent-filter> Keep কোনও মিল নেই; মূল এলিমেন্টের মধ্যে একাধিক ঘোষণা অনুমোদিত।
<manifest> শুধুমাত্র চিল্ড্রেন আইটেম মার্জ করুন প্রতিটি ফাইলে শুধু একটিই আছে।
<meta-data> মার্জ করুন android:name অ্যাট্রিবিউট
<path-permission> মার্জ করুন প্রতি <provider>-এ শুধুমাত্র একটিই আছে।
<permission-group> মার্জ করুন android:name অ্যাট্রিবিউট
<permission> মার্জ করুন android:name অ্যাট্রিবিউট
<permission-tree> মার্জ করুন android:name অ্যাট্রিবিউট
<provider> মার্জ করুন android:name অ্যাট্রিবিউট
<receiver> মার্জ করুন android:name অ্যাট্রিবিউট
<screen> মার্জ করুন android:screenSize অ্যাট্রিবিউট
<service> মার্জ করুন android:name অ্যাট্রিবিউট
<supports-gl-texture> মার্জ করুন android:name অ্যাট্রিবিউট
<supports-screen> মার্জ করুন প্রতি <manifest>-এ শুধুমাত্র একটিই আছে।
<uses-configuration> মার্জ করুন প্রতি <manifest>-এ শুধুমাত্র একটিই আছে।
<uses-feature> মার্জ করুন android:name অ্যাট্রিবিউট (উপস্থিত না থাকলে, android:glEsVersion অ্যাট্রিবিউট)
<uses-library> মার্জ করুন android:name অ্যাট্রিবিউট
<uses-permission> মার্জ করুন android:name অ্যাট্রিবিউট
<uses-sdk> মার্জ করুন প্রতি <manifest>-এ শুধুমাত্র একটিই আছে।
কাস্টম এলিমেন্ট মার্জ করুন কোনও মিল নেই; এগুলি মার্জার টুলের কাছে অজানা এবং সবসময় মার্জ করা ম্যানিফেস্টে অন্তর্ভুক্ত করা হয়।

ম্যানিফেস্টে বিল্ড ভেরিয়েবেল ইনজেক্ট করুন

আপনার build.gradle ফাইলে সংজ্ঞায়িত করা ভেরিয়েবলগুলি AndroidManifest.xml ফাইলে যোগ করতে হলে, manifestPlaceholders প্রপার্টি ব্যবহার করে আপনি তা করতে পারবেন। এই প্রপার্টি কী-ভ্যালু পেয়ারের ম্যাপ নেয়, যেমন এখানে দেখানো হয়েছে:

গ্ৰুভি

android {
    defaultConfig {
        manifestPlaceholders = [hostName:"www.example.com"]
    }
    ...
}

Kotlin

android {
    defaultConfig {
        manifestPlaceholders["hostName"] = "www.example.com"
    }
    ...
}

তারপর আপনি অ্যাট্রিবিউট ভ্যালু হিসেবে ম্যানিফেস্ট ফাইলে প্লেসহোল্ডারগুলির মধ্যে একটি যোগ করতে পারেন:

<intent-filter ... >
    <data android:scheme="https" android:host="${hostName}" ... />
    ...
</intent-filter>

ডিফল্ট হিসেবে, বিল্ড টুল আপনার অ্যাপের অ্যাপ্লিকেশন আইডি ${applicationId} প্লেসহোল্ডারে প্রদান করে। এই ভ্যালু সবসময় বর্তমান বিল্ডের জন্য চূড়ান্ত অ্যাপ্লিকেশন আইডির সাথে মেলে, যার মধ্যে বিল্ড ভেরিয়েন্ট দ্বারা করা পরিবর্তনও অন্তর্ভুক্ত। এটি তখন কাজে লাগে যখন আপনি শনাক্তকারীর জন্য একটি অনন্য নেমস্পেস ব্যবহার করতে চান যেমন একটি ইন্টেন্ট অ্যাকশন, এমনকি আপনার বিল্ড ভেরিয়েন্টের মধ্যেও।

যেমন, আপনার build.gradle ফাইলটি যদি এইরকম দেখতে হয়:

গ্ৰুভি

android {
    defaultConfig {
        applicationId "com.example.myapp"
    }
    flavorDimensions "type"
    productFlavors {
        free {
            applicationIdSuffix ".free"
            dimension "type"
        }
        pro {
            applicationIdSuffix ".pro"
            dimension "type"
        }
    }
}

Kotlin

android {
    defaultConfig {
        applicationId = "com.example.myapp"
    }
    flavorDimensions += "type"
    productFlavors {
        create("free") {
            applicationIdSuffix = ".free"
            dimension = "type"
        }
        create("pro") {
            applicationIdSuffix = ".pro"
            dimension = "type"
        }
    }
}

তারপর আপনি এইভাবে আপনার ম্যানিফেস্টে অ্যাপ্লিকেশন আইডি যোগ করতে পারবেন:

<intent-filter ... >
    <action android:name="${applicationId}.TRANSMOGRIFY" />
    ...
</intent-filter>

এবং আপনি যখন "ফ্রি" প্রোডাক্ট ফ্লেভার তৈরি করেন তখন ম্যানিফেস্ট ফলাফলটি হল:

<intent-filter ... >
   <action android:name="com.example.myapp.free.TRANSMOGRIFY" />
    ...
</intent-filter>

আরও তথ্যের জন্য, অ্যাপ্লিকেশন আইডি সেট করুন নিবন্ধটি পড়ুন।