অ্যান্ড্রয়েড এন্টারপ্রাইজ থেকে ডিভাইস ট্রাস্ট - ইন্টিগ্রেশন গাইড

ডিভাইস ট্রাস্ট সিগন্যাল গ্রহণের উদ্দেশ্যে AMAPI SDK ব্যবহারের জন্য এই ডকুমেন্টটি আপনার প্রাথমিক নির্দেশিকা হওয়া উচিত।

AMAPI SDK আপনার অ্যাপ্লিকেশনটিকে (যাকে আমরা কখনও কখনও "কম্প্যানিয়ন" অ্যাপ হিসেবেও উল্লেখ করতে পারি) ADP (Android ডিভাইস নীতি) অ্যাপ থেকে ডিভাইস ট্রাস্ট সিগন্যাল অ্যাক্সেস করতে সক্ষম করে। এরপর আপনার অ্যাপ এই সিগন্যালগুলি ব্যবহার করে ডিভাইসের ট্রাস্ট অবস্থা গণনা করতে এবং পছন্দ অনুযায়ী ব্যবসায়িক যুক্তি প্রয়োগ করতে পারে।

পূর্বশর্ত

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

আপনার অ্যাপ্লিকেশনে AMAPI SDK এর সাথে একীভূত করুন

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

প্রয়োজনীয় অনুমতি যোগ করুন

ডিভাইস ট্রাস্ট ফ্রম অ্যান্ড্রয়েড এন্টারপ্রাইজ এপিআই থেকে ফিরে আসা কিছু সিগন্যালের জন্য অ্যাপটিকে প্রথমে এই তথ্য অ্যাক্সেস করার জন্য যে অনুমতি প্রয়োজন হবে সেই একই অনুমতি ঘোষণা করতে হবে, বিশেষ করে:

সংকেত প্রয়োজনীয় অনুমতি
নেটওয়ার্ক অবস্থা ACCESS_NETWORK_STATE
স্ক্রিন লকের জটিলতা REQUEST_PASSWORD_COMPLEXITY

যদি এই অনুমতিগুলি অ্যাপের AndroidManifest.xml এ অন্তর্ভুক্ত না করা হয়, তাহলে Android Enterprise API থেকে ডিভাইস ট্রাস্ট সংশ্লিষ্ট সিগন্যালের মেটাডেটাতে PERMISSION_ISSUE ফেরত দেবে:

internalDeviceSettings=DeviceSettings{
  screenLockComplexity=COMPLEXITY_UNSPECIFIED,
  internalScreenLockComplexityMetadata=Metadata{
    dataIssues=[
      DataIssue{
        issueType=PERMISSION_ISSUE,
        issueLevel=WARNING,
        issueDetails=IssueDetailsCase{none}
      }
    ]
  },

আরও তথ্যের জন্য উপলব্ধ ডিভাইস ট্রাস্ট সিগন্যালের তালিকা দেখুন।

ডিভাইসের বিশ্বাস সংকেত অ্যাক্সেস করার ধাপগুলি

যেসব অ্যাপ্লিকেশন ডিভাইস ট্রাস্ট সিগন্যাল অ্যাক্সেস করতে চায় তাদের ক্লায়েন্ট পরিবেশ আপ টু ডেট আছে কিনা তা যাচাই করতে হবে এবং প্রয়োজনে এটি আপডেট করতে হবে।

ডিভাইস ট্রাস্ট সিগন্যাল অ্যাক্সেস করার ধাপগুলি হল:

ডিভাইসের বিশ্বাস সংকেত অ্যাক্সেস করার ধাপগুলি

ক্লায়েন্ট পরিবেশ যাচাই করুন

নিম্নলিখিত কোড উদাহরণে ADP অ্যাপের বর্তমান অবস্থা পড়ার জন্য getEnvironment ব্যবহার করার পদ্ধতি দেখানো হয়েছে। পরিবেশ প্রস্তুত এবং আপ টু ডেট থাকলে আপনার অ্যাপ্লিকেশনটি ডিভাইস ট্রাস্ট সিগন্যাল অ্যাক্সেস করার জন্য একটি deviceClient তৈরি করতে পারে ( অ্যাক্সেস ডিভাইস ট্রাস্ট সিগন্যাল দেখুন)।

কোটলিন

import com.google.android.managementapi.common.model.Role
import com.google.android.managementapi.device.DeviceClient
import com.google.android.managementapi.device.DeviceClientFactory
import com.google.android.managementapi.device.model.GetDeviceRequest
import com.google.android.managementapi.environment.EnvironmentClient
import com.google.android.managementapi.environment.EnvironmentClientFactory
import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.INSTALLED
import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.NOT_INSTALLED
import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.READY
import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.Version.UP_TO_DATE
import com.google.android.managementapi.environment.model.GetEnvironmentRequest
import com.google.android.managementapi.environment.model.PrepareEnvironmentRequest

try {
    val context = applicationContext

    val roles = listOf(Role.builder().setRoleType(Role.RoleType.IDENTITY_PROVIDER).build())
    val request = GetEnvironmentRequest.builder().setRoles(roles).build()
    val environmentClient = EnvironmentClientFactory.create(context)
    val environmentResponse = environmentClient.getEnvironment(request)

    if (environmentResponse.hasAndroidDevicePolicyEnvironment()) {
        val adpEnvironment = environmentResponse.androidDevicePolicyEnvironment

        if (adpEnvironment.state == READY && adpEnvironment.version == UP_TO_DATE) {
            // AMAPI Environment State OK, Version OK.  Requesting Device signals..
            checkDevice(deviceClient = DeviceClientFactory.create(context))
        } else if (adpEnvironment.state == INSTALLED) {
            // prepareEnvironment should be called, calling
            // prepareEnvironment won't show the UI
            prepareEnvironment(context, environmentClient)
        } else if (adpEnvironment.state == NOT_INSTALLED) {
            // prepareEnvironment should be called, calling
            // prepareEnvironment will show the UI
            prepareEnvironment(context, environmentClient)
        }
    }
} catch (e: Exception) {
    Log.e(TAG, "Exception", e)
}

জাভা

import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.INSTALLED;
import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.NOT_INSTALLED;
import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.READY;
import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.Version.UP_TO_DATE;

import com.google.android.managementapi.common.model.Role;
import com.google.android.managementapi.device.DeviceClient;
import com.google.android.managementapi.device.DeviceClientFactory;
import com.google.android.managementapi.device.model.Device;
import com.google.android.managementapi.device.model.GetDeviceRequest;
import com.google.android.managementapi.environment.EnvironmentClient;
import com.google.android.managementapi.environment.EnvironmentClientFactory;
import com.google.android.managementapi.environment.model.Environment;
import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment;
import com.google.android.managementapi.environment.model.GetEnvironmentRequest;
import com.google.android.managementapi.environment.model.PrepareEnvironmentRequest;
import com.google.android.managementapi.environment.model.PrepareEnvironmentResponse;

try {
    Context context = getApplicationContext();

    ImmutableList roles = new ImmutableList.Builder()
            .add(Role.builder()
                    .setRoleType(Role.RoleType.IDENTITY_PROVIDER)
                    .build())
            .build();

    EnvironmentClient environmentClient = EnvironmentClientFactory.create(context);
    GetEnvironmentRequest request = GetEnvironmentRequest.builder()
            .setRoles(roles)
            .build();

    ListenableFuture getEnvironmentFuture = environmentClient.getEnvironmentAsync(request);
    Futures.addCallback(getEnvironmentFuture, new FutureCallback<>() {
        @Override
        public void onSuccess(Environment environment) {
            AndroidDevicePolicyEnvironment adpEnvironment = environment.getAndroidDevicePolicyEnvironment();

            AndroidDevicePolicyEnvironment.State state = adpEnvironment.getState();
            AndroidDevicePolicyEnvironment.Version version = adpEnvironment.getVersion();
            if (state == READY && version == UP_TO_DATE) {
                // AMAPI Environment State OK, Version OK.  Requesting Device signals..
                DeviceClient deviceClient = DeviceClientFactory.create(context);
                checkDevice(deviceClient);
            } else if (state == INSTALLED) {
                // prepareEnvironment should be called, calling
                // prepareEnvironment won't show the UI
                prepareEnvironment(context, environmentClient);
            } else if (state == NOT_INSTALLED) {
                // prepareEnvironment should be called, calling
                // prepareEnvironment will show the UI
                prepareEnvironment(context, environmentClient);
            }
        }

        @Override
        public void onFailure(Throwable t) {
            Log.d(TAG, t.toString());
        }
    }, MoreExecutors.directExecutor());
} catch (Exception e) {
    Log.d(TAG, e.toString());
}

যদি ADP অ্যাপটি ইনস্টল করা থাকে কিন্তু আপ টু ডেট না থাকে, তাহলে আপনার অ্যাপ্লিকেশনটি prepareEnvironment কল করে ব্যবহারকারীর হস্তক্ষেপ ছাড়াই নীরবে ADP অ্যাপটি আপডেট করবে।

যদি ADP অ্যাপটি ইনস্টল না থাকে, তাহলে আপনার অ্যাপ্লিকেশনটি prepareEnvironment কল করে ব্যবহারকারীকে ADP অ্যাপটি ইনস্টল করার জন্য অনুরোধ করতে পারে। ক্লায়েন্ট পরিবেশ প্রস্তুত করুন দেখুন।

ক্লায়েন্ট পরিবেশ প্রস্তুত করুন

  • যদি ADP অ্যাপটি ইতিমধ্যেই ইনস্টল করা থাকে, তাহলে API ব্যবহারকারীর হস্তক্ষেপ ছাড়াই নীরবে এটি আপডেট করবে।

  • যদি ADP অ্যাপটি ইনস্টল না করা থাকে, তাহলে API ব্যবহারকারীকে ADP অ্যাপের ইনস্টলেশন গ্রহণ করতে অনুরোধ করবে।

অ্যান্ড্রয়েড ডিভাইস নীতি ইনস্টল করুন

ব্যবহারকারীর পছন্দ পর্যবেক্ষণ করার জন্য একটি কলব্যাক নিবন্ধন করা সম্ভব। অতিরিক্ত তথ্যের জন্য ADP অ্যাপ ইনস্টলেশনের সময় ব্যবহারকারীর মিথস্ক্রিয়া ট্র্যাক করুন দেখুন।

আমরা সুপারিশ করছি যে অনবোর্ডিং UX ফ্লো চলাকালীন, prepareEnvironment কলটি একটি ফোরগ্রাউন্ড প্রক্রিয়া থেকে করা হোক, যাতে ব্যবহারকারীরা "ইনস্টল অ্যান্ড্রয়েড ডিভাইস পলিসি" মডেল ডায়ালগ ব্যবহার করে অবাক না হন। যদি ফোরগ্রাউন্ড প্রক্রিয়া থেকে কল করা সম্ভব না হয়, কারণ এটি একটি ওয়েব ফ্লো এবং অ্যান্ড্রয়েড কম্পোনেন্টের কোনও UI নেই, তাহলে ব্যাকগ্রাউন্ড থেকে কল করার অনুমতি রয়েছে, কারণ এটি অনবোর্ডিং UX ফ্লো চলাকালীন ঘটতে হবে।

একবার পরিবেশ সঠিকভাবে সেট আপ হয়ে গেলে, ডিভাইস ট্রাস্ট সিগন্যাল অ্যাক্সেস করা সম্ভব। অ্যাক্সেস ডিভাইস ট্রাস্ট সিগন্যাল দেখুন।

কোটলিন

try {
    val myNotificationReceiverService = ComponentName(
        context, MyNotificationReceiverService::class.java
    )

    val roles = listOf(Role.builder().setRoleType(Role.RoleType.IDENTITY_PROVIDER).build())
    val request = PrepareEnvironmentRequest.builder().setRoles(roles).build()

    val response =
        environmentClient.prepareEnvironment(request, myNotificationReceiverService)

    val environment = response.environment
    val adpEnvironment = environment.androidDevicePolicyEnvironment

    val state = adpEnvironment.state
    val version = adpEnvironment.version
    if (state == READY && version == UP_TO_DATE) {
        // Environment is prepared, access device posture signals using
        // DeviceClient.
        checkDevice(deviceClient = DeviceClientFactory.create(context))
    } else {
        // The prepareEnvironment call failed to prepare
        Log.w(
            TAG, "AMAPI environment was not ready: " + state + " - " + version
        )
    }

} catch (e: java.lang.Exception) {
    Log.d(TAG, e.toString())
}

জাভা

try {
    ComponentName myNotificationReceiverService = new ComponentName(
            context,
            MyNotificationReceiverService.class
    );

    ImmutableList roles = new ImmutableList.Builder()
            .add(Role.builder()
                    .setRoleType(Role.RoleType.IDENTITY_PROVIDER)
                    .build())
            .build();


    PrepareEnvironmentRequest request = PrepareEnvironmentRequest.builder()
            .setRoles(roles)
            .build();

    ListenableFuture environmentFuture =
            environmentClient.prepareEnvironmentAsync(
                    request,
                    myNotificationReceiverService
            );

    Futures.addCallback(environmentFuture, new FutureCallback<>() {
        @Override
        public void onSuccess(PrepareEnvironmentResponse response) {
            Environment environment = response.getEnvironment();
            AndroidDevicePolicyEnvironment adpEnvironment = environment.getAndroidDevicePolicyEnvironment();

            AndroidDevicePolicyEnvironment.State state = adpEnvironment.getState();
            AndroidDevicePolicyEnvironment.Version version = adpEnvironment.getVersion();
            if (state == READY && version == UP_TO_DATE) {
                // AMAPI Environment State OK, Version OK.  Requesting Device signals..
                DeviceClient deviceClient = DeviceClientFactory.create(context);
                checkDevice(deviceClient);
            } else {
                // The prepareEnvironment call failed to prepare
                Log.w(
                        TAG, "AMAPI environment was not ready: "
                        + adpEnvironment.getState() + " - " + adpEnvironment.getVersion()
                );
            }
        }

        @Override
        public void onFailure(@NonNull Throwable t) {
            // Handle the error
            Log.d(TAG, "AMAPI response did not contain an ADP environment");
        }
    }, MoreExecutors.directExecutor());
} catch (Exception e) {
    Log.d(TAG, e.toString());
}

ডিভাইসের বিশ্বাসের সংকেত অ্যাক্সেস করুন

আপনার আগ্রহের ডিভাইস ট্রাস্ট সিগন্যালগুলি অ্যাক্সেস করতে, আপনি আগের ধাপে দেখা deviceClient ইনস্ট্যান্স ব্যবহার করে Device অবজেক্টটি অনুরোধ করতে পারেন।

কোটলিন

try {
    kotlin.runCatching {
        deviceClient.getDeviceAwait(GetDeviceRequest.getDefaultInstance())
    }.onFailure { t ->
        Log.d(TAG, t.toString())
    }.onSuccess { device ->
        // Access device posture signals available in device
        val deviceString = device.toString()
        Log.d(TAG, deviceString)
    }
} catch (e: java.lang.Exception) {
    Log.d(TAG, e.toString())
}

জাভা

try {
    ListenableFuture deviceFuture =
            deviceClient.getDevice(GetDeviceRequest.getDefaultInstance());

    Futures.addCallback(deviceFuture, new FutureCallback() {
        @Override
        public void onSuccess(Device device) {
            // Access device posture signals available in device
            String deviceString = device.toString();
            Log.d(TAG, deviceString);
        }

        @Override
        public void onFailure(Throwable t) {
            Log.d(TAG, Log.d(TAG, t.toString());
        }
    }, MoreExecutors.directExecutor());
} catch (Exception e) {
    Log.d(TAG, e.toString());
}

ত্রুটিগুলি পরিচালনা করুন

যদি আপনার অ্যাপটি ডিভাইস ট্রাস্ট রিকোয়েস্ট করে এবং কলটি ব্যর্থ হয়, তাহলে আপনার অ্যাপটি একটি ব্যতিক্রম পাবে। এই ব্যতিক্রমগুলি বিভিন্ন কারণে ঘটতে পারে, যেমন:

  • SecurityException - আপনার অ্যাপটি ডিভাইস ট্রাস্ট সিগন্যাল অ্যাক্সেস করার জন্য নিবন্ধিত নয়। ডিভাইস ট্রাস্ট সিগন্যাল অ্যাক্সেস দেখুন।
  • AmapiSdkException - ADP এর একটি সাবক্লাস উপস্থিত নেই অথবা প্রস্তুত নয়। এটি একটি ক্ষণস্থায়ী অবস্থার কারণে হতে পারে এবং আপনার পুনরায় কল করার চেষ্টা করা উচিত।

পুনরায় চেষ্টা করার কৌশল

ক্ষণস্থায়ী অবস্থার কারণে ব্যতিক্রমের জন্য সূচকীয় ব্যাকঅফ সহ একটি পুনঃচেষ্টা কৌশল প্রয়োগ করুন। প্রথম ব্যর্থতার পরে, পুনরায় চেষ্টা করার আগে 5 সেকেন্ডের প্রাথমিক বিলম্ব দিয়ে শুরু করুন।

প্রতিবার সূচকীয়ভাবে বর্ধিত বিলম্ব (১০, ২০, ইত্যাদি) ব্যবহার করে প্রস্থান শর্ত হিসাবে সর্বাধিক সংখ্যক প্রচেষ্টা সহ একটি পুনঃচেষ্টা কৌশল বাস্তবায়ন করুন।

ADP অ্যাপ ইনস্টলেশনের সময় ব্যবহারকারীর মিথস্ক্রিয়া ট্র্যাক করুন

যদি prepareEnvironment সময় ডিভাইসটির ADP অ্যাপ ইনস্টল করার প্রয়োজন হয়, তাহলে আপনার অ্যাপ্লিকেশনটি NotificationReceiverService প্রয়োগ করে ব্যবহারকারীর ইন্টারঅ্যাকশন ট্র্যাক করতে পারে, যা getPrepareEnvironmentListener কে ওভাররাইড করে বিজ্ঞপ্তিগুলি গ্রহণ করে:

কোটলিন

import android.util.Log
import com.google.android.managementapi.environment.EnvironmentListener
import com.google.android.managementapi.environment.model.EnvironmentEvent.EventCase.Kind.ANDROID_DEVICE_POLICY_INSTALL_CONSENT_ACCEPTED
import com.google.android.managementapi.environment.model.EnvironmentEvent
import com.google.android.managementapi.notification.NotificationReceiverService

class MyNotificationReceiverService : NotificationReceiverService() {
    override fun getPrepareEnvironmentListener(): EnvironmentListener {
        return MyEnvironmentListener()
    }
}

class MyEnvironmentListener : EnvironmentListener {
    override fun onEnvironmentEvent(
        event: EnvironmentEvent
    ) {
        if (event.event.kind == ANDROID_DEVICE_POLICY_INSTALL_CONSENT_ACCEPTED) {
            Log.d(TAG, "User provided install consent")
        } else {
            Log.d(TAG, "User rejected install consent")
        }
    }

    companion object {
        private val TAG: String = MyEnvironmentListener::class.java.simpleName
    }
}

জাভা

import static com.google.android.managementapi.environment.model.EnvironmentEvent.EventCase.Kind.ANDROID_DEVICE_POLICY_INSTALL_CONSENT_ACCEPTED;

import android.util.Log;
import androidx.annotation.NonNull;
import com.google.android.managementapi.environment.EnvironmentListener;
import com.google.android.managementapi.environment.model.EnvironmentEvent;
import com.google.android.managementapi.notification.NotificationReceiverService;

class MyNotificationReceiverService extends NotificationReceiverService {
    @NonNull
    @Override
    protected EnvironmentListener getPrepareEnvironmentListener() {
        return new MyEnvironmentListener();
    }
}
class MyEnvironmentListener implements EnvironmentListener {
    final private String TAG = MyEnvironmentListener.class.getSimpleName();

    @Override
    public void onEnvironmentEvent(EnvironmentEvent event) {
        if (event.getEvent().getKind() == ANDROID_DEVICE_POLICY_INSTALL_CONSENT_ACCEPTED)
        {
            Log.d(TAG, "User provided install consent");
        } else {
            Log.d(TAG, "User rejected install consent");
        }
    }
}

জ্ঞাত সমস্যা

এই মুহূর্তে কোন পরিচিত সমস্যা নেই।