এক্সটেনশন অ্যাপ ও স্থানীয় কমান্ড

Android Management API (AMAPI) SDK, EMM-নির্দিষ্ট এক্সটেনশন অ্যাপকে Android Device Policy (ADP)-এর সাথে সরাসরি যোগাযোগ করতে এবং ডিভাইসে Commands এক্সিকিউট করতে দেয়।

AMAPI SDK-এর সাথে ইন্টিগ্রেট করুন এই লাইব্রেরি এবং কীভাবে এটি আপনার অ্যাপ্লিকেশনে যোগ করবেন সে সম্পর্কে আরও তথ্য প্রদান করে।

SDK ইন্টিগ্রেট করা হয়ে গেলে, আপনার এক্সটেনশন অ্যাপ ADP-এর সাথে যোগাযোগ করতে পারবে, যাতে:

কমান্ড ইস্যু করুন

একটি এক্সটেনশন অ্যাপ ADP ব্যবহার করে কমান্ড ইস্যু করার জন্য অনুরোধ করতে পারে। IssueCommandRequest-এ অনুরোধ অবজেক্ট থাকে যাতে ইস্যু করা কমান্ড ও নির্দিষ্ট প্যারামিটার সম্পর্কে বিস্তারিত তথ্য থাকে।

অ্যাপ ডেটা সাফ করুন

প্যাকেজের ডেটা মুছে ফেলার অনুরোধ কীভাবে করতে হয় তা নিম্নলিখিত স্নিপেট থেকে জানতে পারবেন:

import android.util.Log;
...
import com.google.android.managementapi.commands.LocalCommandClientFactory;
import com.google.android.managementapi.commands.model.Command;
import com.google.android.managementapi.commands.model.GetCommandRequest;
import com.google.android.managementapi.commands.model.IssueCommandRequest;
import com.google.android.managementapi.commands.model.IssueCommandRequest.ClearAppsData;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;

...
  void issueClearAppDataCommand(ImmutableList<String> packageNames) {
    Futures.addCallback(
        LocalCommandClientFactory.create(getContext())
            .issueCommand(createClearAppRequest(packageNames)),
        new FutureCallback<Command>() {
          @Override
          public void onSuccess(Command result) {
            // Process the returned command result here
            Log.i(TAG, "Successfully issued command");
          }

          @Override
          public void onFailure(Throwable t) {
            Log.e(TAG, "Failed to issue command", t);
          }
        },
        MoreExecutors.directExecutor());
  }

  IssueCommandRequest createClearAppRequest(ImmutableList<String> packageNames) {
    return IssueCommandRequest.builder()
        .setClearAppsData(
            ClearAppsData.builder()
                .setPackageNames(packageNames)
                .build()
        )
        .build();
  }
...

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

ডিভাইস বা অফিস প্রোফাইল ওয়াইপ করা

আইটি অ্যাডমিন LOCAL_DEVICE_WIPE_COMMAND_ALLOWED অতিরিক্ত ক্ষমতা সহ COMPANION_APP ভূমিকা অ্যাসাইন করলে, কম্প্যানিয়ন অ্যাপ স্থানীয় Wipe কমান্ড ইস্যু করতে পারে। কোম্পানির মালিকানাধীন ডিভাইসের ক্ষেত্রে, এটি ডিভাইস ফ্যাক্টরি রিসেট করে; অফিস প্রোফাইল সহ ব্যক্তিগত মালিকানাধীন ডিভাইসের ক্ষেত্রে, এটি অফিস প্রোফাইল সরিয়ে দেয়। অ্যাপের এই ভূমিকা ও অতিরিক্ত ক্ষমতা না থাকলে, অনুরোধটি সম্পূর্ণ হয় না। আরও বিবরণের জন্য, নীতি কনফিগারেশন দেখুন।

দুটি Wipe প্যারামিটারই ঐচ্ছিক। আপনি কোনও ভ্যালু নির্দিষ্ট করতে না চাইলে, বিল্ডার সেটার বাদ দিন অথবা খালি কালেকশন বা খালি স্ট্রিং পাস করুন (null পাস করবেন না)।

  • WipeDataFlag ভ্যালু কোন ডেটা মুছে ফেলা হবে তা নিয়ন্ত্রণ করে:
    • PRESERVE_RESET_PROTECTION_DATA: ফ্যাক্টরি রিসেট প্রোটেকশন ডেটা রেখে দেয়, যা ডিফল্ট হিসেবে মুছে যায়। শুধুমাত্র কোম্পানির মালিকানাধীন ডিভাইসের ক্ষেত্রে প্রযোজ্য।
    • WIPE_EXTERNAL_STORAGE: এছাড়াও, এসডি কার্ডের মতো এক্সটার্নাল স্টোরেজ মুছে দেয়। শুধুমাত্র কোম্পানির মালিকানাধীন ডিভাইসের ক্ষেত্রে প্রযোজ্য।
    • WIPE_ESIMS: কোম্পানির মালিকানাধীন ডিভাইস থেকে সব eSIM সরিয়ে দেয়। ব্যক্তিগত মালিকানাধীন ডিভাইসে, শুধুমাত্র ম্যানেজ করা ই-সিম সরিয়ে দেয় (Android 16 বা তার পরবর্তী ভার্সনে, ম্যানেজ করা ই-সিম সবসময় অফিস প্রোফাইলের সাথে সরিয়ে দেওয়া হয়, এই ফ্ল্যাগ সেট করা থাকুক বা না থাকুক)।
  • wipeReason: ব্যক্তিগত মালিকানাধীন ডিভাইস থেকে অফিস প্রোফাইল সরিয়ে দেওয়া হলে, ব্যবহারকারীকে দেখানো ২০০ অক্ষরের মধ্যে একটি ছোট মেসেজ। কোম্পানির মালিকানাধীন ডিভাইসে এর কোনও প্রভাব পড়ে না।

নিম্নলিখিত স্নিপেট থেকে জানা যায় যে ডিভাইস বা অফিস প্রোফাইল মুছে দেওয়ার অনুরোধ কীভাবে করতে হয়:

Kotlin

import android.content.Context
import android.util.Log
...
import com.google.android.managementapi.commands.CommandException
import com.google.android.managementapi.commands.LocalCommandClientFactory
import com.google.android.managementapi.commands.model.IssueCommandRequest
import com.google.android.managementapi.commands.model.IssueCommandRequest.Wipe
import com.google.android.managementapi.commands.model.IssueCommandRequest.Wipe.WipeDataFlag

...
  suspend fun issueWipeCommand(
      context: Context,
      wipeDataFlags: List<WipeDataFlag>,
      wipeReason: String,
  ) {
    try {
      val command =
          LocalCommandClientFactory.create(context)
              .issueCommandAwait(createWipeRequest(wipeDataFlags, wipeReason))
      Log.i(TAG, "Successfully issued wipe command: ${command.commandId}")
    } catch (e: CommandException) {
      Log.e(TAG, "Failed to issue wipe command", e)
    }
  }

  fun createWipeRequest(
      wipeDataFlags: List<WipeDataFlag>,
      wipeReason: String,
  ): IssueCommandRequest =
      IssueCommandRequest.builder()
          .setWipe(
              Wipe.builder()
                  .setWipeDataFlags(wipeDataFlags)
                  .setWipeReason(wipeReason)
                  .build()
          )
          .build()
...

Java

import android.content.Context;
import android.util.Log;
...
import com.google.android.managementapi.commands.LocalCommandClientFactory;
import com.google.android.managementapi.commands.model.Command;
import com.google.android.managementapi.commands.model.IssueCommandRequest;
import com.google.android.managementapi.commands.model.IssueCommandRequest.Wipe;
import com.google.android.managementapi.commands.model.IssueCommandRequest.Wipe.WipeDataFlag;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;

...
  void issueWipeCommand(
      Context context,
      ImmutableList<WipeDataFlag> wipeDataFlags,
      String wipeReason) {
    Futures.addCallback(
        LocalCommandClientFactory.create(context)
            .issueCommand(createWipeRequest(wipeDataFlags, wipeReason)),
        new FutureCallback<Command>() {
          @Override
          public void onSuccess(Command result) {
            Log.i(TAG, "Successfully issued wipe command: " + result.getCommandId());
          }

          @Override
          public void onFailure(Throwable t) {
            Log.e(TAG, "Failed to issue wipe command", t);
          }
        },
        MoreExecutors.directExecutor());
  }

  IssueCommandRequest createWipeRequest(
      ImmutableList<WipeDataFlag> wipeDataFlags, String wipeReason) {
    return IssueCommandRequest.builder()
        .setWipe(
            Wipe.builder()
                .setWipeDataFlags(wipeDataFlags)
                .setWipeReason(wipeReason)
                .build())
        .build();
  }
...

কমান্ড পান

এক্সটেনশন অ্যাপ আগে ইস্যু করা কমান্ড অনুরোধের স্ট্যাটাস কোয়েরি করতে পারে। কমান্ডের স্ট্যাটাস জানতে, আপনার কমান্ড আইডি (ইস্যু কমান্ড অনুরোধ থেকে উপলভ্য) প্রয়োজন হবে। নিম্নলিখিত স্নিপেট থেকে জানা যায় যে কীভাবে ADP-তে GetCommandRequest পাঠাতে হয়।

import android.util.Log;
...
import com.google.android.managementapi.commands.LocalCommandClientFactory;
...
import com.google.android.managementapi.commands.model.GetCommandRequest;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;

...
  void getCommand(String commandId) {
    Futures.addCallback(
        LocalCommandClientFactory.create(getApplication())
            .getCommand(GetCommandRequest.builder().setCommandId(commandId).build()),
        new FutureCallback<Command>() {
          @Override
          public void onSuccess(Command result) {
            // Process the returned command result here
            Log.i(Constants.TAG, "Successfully issued command");
          }

          @Override
          public void onFailure(Throwable t) {
            Log.e(Constants.TAG, "Failed to issue command", t);
          }
        },
        MoreExecutors.directExecutor());
  }
  ...

কমান্ড স্ট্যাটাস পরিবর্তন কলব্যাক শুনুন

এইসব ধাপ অনুসরণ করে দীর্ঘ সময় ধরে চলা কমান্ডের স্ট্যাটাস পরিবর্তনের আপডেট পেতে, একটি এক্সটেনশন অ্যাপ ঐচ্ছিকভাবে কলব্যাক রেজিস্টার করতে পারে:

  1. কমান্ড স্ট্যাটাস পরিবর্তন CommandListener-কে জানানো হয়, আপনার অ্যাপে এই ইন্টারফেস প্রয়োগ করুন এবং প্রাপ্ত স্ট্যাটাস আপডেট কীভাবে ম্যানেজ করবেন সেই বিষয়ে প্রয়োগের পদ্ধতি প্রদান করুন।
  2. NotificationReceiverService এক্সটেন্ড করুন এবং getCommandListener পদ্ধতির মাধ্যমে CommandListener ইনস্ট্যান্স প্রদান করুন।
  3. আপনার অ্যাপে COMPANION_APP ভূমিকা অ্যাসাইন করতে অ্যাপ্লিকেশন নীতি কনফিগার করুন (নীতি কনফিগারেশন দেখুন)।

    import com.google.android.managementapi.commands.CommandListener;
    import com.google.android.managementapi.notification.NotificationReceiverService;
    
    ...
    
    public class SampleCommandService extends NotificationReceiverService {
    
     @Override
     public CommandListener getCommandListener() {
       // return the concrete implementation from previous step
       return ...;
     }
    }
    

নীতি কনফিগারেশন

কম্প্যানিয়ন অ্যাপকে সরাসরি ADP-এর সাথে যোগাযোগ করার অনুমতি দিতে, EMM-কে অ্যাপ্লিকেশন নীতির roles ফিল্ড ব্যবহার করে অ্যাপে COMPANION_APP ভূমিকা অ্যাসাইন করতে হবে:

 "applications": [{
   "packageName": "com.amapi.extensibility.demo",
   "installType": "FORCE_INSTALLED",
   "roles": [
     { "roleType": "COMPANION_APP" }
   ]
 }]

কম্প্যানিয়ন অ্যাপকে লোকাল Wipe কমান্ড ইস্যু করার অনুমতি দিতে, extraCapabilities.localDeviceWipeCommand-কে LOCAL_DEVICE_WIPE_COMMAND_ALLOWED হিসেবে সেট করুন:

 "applications": [{
   "packageName": "com.amapi.extensibility.demo",
   "installType": "FORCE_INSTALLED",
   "roles": [
     {
       "roleType": "COMPANION_APP",
       "extraCapabilities": {
         "localDeviceWipeCommand": "LOCAL_DEVICE_WIPE_COMMAND_ALLOWED"
       }
     }
   ]
 }]

উপলভ্য অতিরিক্ত বিকল্পের জন্য অ্যাপ রোল নীতির মাধ্যমে ডিভাইস প্রোভিশন করুন দেখুন।

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

পরীক্ষা করা

ইউনিট টেস্টিং

LocalCommandClient হল একটি ইন্টারফেস এবং তাই এটি টেস্ট করা যায় এমন ইমপ্লিমেন্টেশন প্রদান করার অনুমতি দেয়।

ইন্টিগ্রেশন টেস্টিং

ADP-এর সাথে পরীক্ষা করার জন্য নিম্নলিখিত তথ্য প্রয়োজন হবে:

  1. এক্সটেনশন অ্যাপের প্যাকেজের নাম।
  2. অ্যাপ প্যাকেজের সাথে যুক্ত স্বাক্ষরের base64-এনকোড করা SHA-256 হ্যাশ।
  3. বিকল্প হিসেবে, কলব্যাক পরীক্ষা করার জন্য - কলব্যাক সমর্থন করার জন্য নতুন চালু করা পরিষেবা থেকে পরিষেবার সম্পূর্ণ নাম। (উদাহরণে CommandService-এর সম্পূর্ণ নাম)।