ورود و عضویت
0
سبد خرید شما خالی است
0
سبد خرید شما خالی است

پیاده سازی Deep link در فلاتر

7 دیدگاه

اگر با اپلیکیشن اینستاگرام کار کرده باشید متوجه میشید زمانی که وارد وبسایت آن میشوید به صورت خودکار به اپلیکیشن اینستاگرام که روی گوشی نصب شده برگشت داده می شوید.

این قابلیت با استفاده از Depp link پیاده سازی می شود.

شما به راحتی میتوانید آدرس های url خاصی را در برنامه خود تعریف کنید تا کاربر با وارد شدن به آن لینک به اپلیکیشن برگشت داده شود.

یکی از مثال های دیگر استفاده از Depp link برای زمانی هست از درگاه پرداخت استفاده میکنید و کاربر از صفحه بانک به اپلیکیشن بازگردانده می شود.

قبل از انجام کارهای کدنویسی باید یک سری تنظیمات در پروژه انجام دهیم.

برای سیستم عامل iOS به دو روش میتونیم دیپ لینک را پیاده سازی کنیم.

Custom URL schemes: این روش به شما امکان کار کردن با هر نوع ترتیب یا طرحی را میدهد و نیازی به انتخاب کردن هاست یا دامنه اینترنتی ندارید. اما لازم هست تا طرحی که استفاده میکنید منحصر به فرد باشد.

برای مثال با آدرسی به شکل زیر میتونید کار کنید.

your_scheme://any_host

Universal Links: این نوع به شما امکان کار کردن با ادرس های مبتنی بر پروتکل https را میدهد اما فقط باید از دامنه ای که مشخص کردید استفاده کنید.

در این آموزش از روش اول برای پیاده سازی در فلاتر استفاده میکنیم.

وارد فایل Info.plist شوید و خط های زیر را وارد کنید.

<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>deeplink.flutter.dev</string>
<key>CFBundleURLSchemes</key>
<array>
<string>poc</string>
</array>
</dict>
</array>

با دستورات اگر وارد آدرس زیر شویم به اپلیکیشن برمیگردیم.

poc://deeplink.flutter.dev

برای اندروید هم دقیقا دو روش برای پیاده سازی Deep Link وجود دارد.

App Links: این روش به شما امکان کار کردن با https را میدهد و نیازمند تعریف کردن هاست یا ادرس سایت هستید.

Deep Links: این روش هم دقیقا مشابه Custom URL schemes هست.

برای انجام تنظیمات در اندروید باید وارد فایل مانیفست که حکم تنظیمات اپلیکیشن را دارد وارد شوید.

<intent-filter>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data
    android:scheme="poc"
    android:host="deeplink.flutter.dev" />
</intent-filter>

آماده سازی Platform Channels

تنظیمات بخش نیتیو برنامه را انجام دادیم. اما برای برقراری ارتباط فلاتر با بخش نیتیو نیاز به استفاده از Platform Channels داریم.

در اندروید نیاز داریم تا Intent  های ورودی را در متد onCreate دریافت کنیم.

پس یک MethodChannel طراحی میکنیم و اگر اپلیکیشن توسط لینک باز شد URI را ارسال میکنیم به این متد.

private val CHANNEL = "poc.deeplink.flutter.dev/channel"
private var startString: String? = null
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
    GeneratedPluginRegistrant.registerWith(flutterEngine)

    MethodChannel(flutterEngine.dartExecutor, CHANNEL).setMethodCallHandler { call, result ->
        if (call.method == "initialLink") {
            if (startString != null) {
                result.success(startString)
            }
        }
    }
}
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val intent = getIntent()
    startString = intent.data?.toString()
}

برای iOS کمی پیاده سازی متفاوت است اما کلیت کار یکی هست و در صورت باز شدن برنامه یک URI ارسال میکنیم.

فایل AppDelegate.swift:

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  
  private var methodChannel: FlutterMethodChannel?
  
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
  ) -> Bool {
    
    let controller = window.rootViewController as! FlutterViewController
    methodChannel = FlutterMethodChannel(name: "poc.deeplink.flutter.dev/cnannel", binaryMessenger: controller)
   
    methodChannel?.setMethodCallHandler({ (call: FlutterMethodCall, result: FlutterResult) in
      guard call.method == "initialLink" else {
        result(FlutterMethodNotImplemented)
        return
      }
    })
    
    
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

تا به اینجا شروع شدن برنامه توسط Deep Link را پیاده سازی کردیم.

اما اگر از قبل اپلیکیشن در حال اجرا بود چه کاری باید انجام دهیم؟

در اندروید متد onNewIntent را بازنویسی میکنیم تا Intent های جدید را پردازش کنیم.

اگر این لینک شامل اکشن بود یک event به EventChannel ارسال میکنیم.

private val EVENTS = "poc.deeplink.flutter.dev/events"
private var linksReceiver: BroadcastReceiver? = null

override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
    GeneratedPluginRegistrant.registerWith(flutterEngine)

    EventChannel(flutterEngine.dartExecutor, EVENTS).setStreamHandler(
            object : EventChannel.StreamHandler {
                override fun onListen(args: Any?, events: EventSink) {
                    linksReceiver = createChangeReceiver(events)
                }

                override fun onCancel(args: Any?) {
                    linksReceiver = null
                }
            }
    )
}
override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    if (intent.action === Intent.ACTION_VIEW) {
        linksReceiver?.onReceive(this.applicationContext, intent)
    }
}


fun createChangeReceiver(events: EventSink): BroadcastReceiver? {
    return object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) { // NOTE: assuming intent.getAction() is Intent.ACTION_VIEW
            val dataString = intent.dataString ?:
            events.error("UNAVAILABLE", "Link unavailable", null)
            events.success(dataString)
        }
    }
}

در بخش iOS هم همینکار و انجام میدیم با کمی تفاوت.

آموزش چند زبانه کردن برنامه Flutter

در زبان سویفت برای این که لینک های ورودی را زمانی که برنامه در بک گراند در حال اجرا است را مدیریت کنیم باید یک FlutterStreamHandler ایجاد کنیم.

فایل AppDelegate.swift را به شکل زیر تغییر دهید.

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  private var eventChannel: FlutterEventChannel?
  
  private let linkStreamHandler = LinkStreamHandler()
  
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
  ) -> Bool {
    
    let controller = window.rootViewController as! FlutterViewController
    eventChannel = FlutterEventChannel(name: "poc.deeplink.flutter.dev/events", binaryMessenger: controller)
       
    GeneratedPluginRegistrant.register(with: self)
    eventChannel?.setStreamHandler(linkStreamHandler)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
  
  override func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
    eventChannel?.setStreamHandler(linkStreamHandler)
    return linkStreamHandler.handleLink(url.absoluteString)
  }
}


class LinkStreamHandler:NSObject, FlutterStreamHandler {
  
  var eventSink: FlutterEventSink?
  
  // links will be added to this queue until the sink is ready to process them
  var queuedLinks = [String]()
  
  func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
    self.eventSink = events
    queuedLinks.forEach({ events($0) })
    queuedLinks.removeAll()
    return nil
  }
  
  func onCancel(withArguments arguments: Any?) -> FlutterError? {
    self.eventSink = nil
    return nil
  }
  
  func handleLink(_ link: String) -> Bool {
    guard let eventSink = eventSink else {
      queuedLinks.append(link)
      return false
    }
    eventSink(link)
    return true
  }
}

یکی از معماری های محبوب در برنامه نویسی فلاتر استفاده از بلاک می باشد که تا به حال آموزش های زیادی هم از آن قرار داده ایم.

کلاس بلاک را به شکل زیر با استفاده از State سراسری کدنویسی میکنیم.

class DeepLinkBloc extends Bloc {

  //Event Channel creation
  static const stream = const EventChannel('poc.deeplink.flutter.dev/events');

  //Method channel creation
  static const platform = const MethodChannel('poc.deeplink.flutter.dev/channel');

  StreamController<String> _stateController = StreamController();

  Stream<String> get state => _stateController.stream;

  Sink<String> get stateSink => _stateController.sink;


  //Adding the listener into contructor
  DeepLinkBloc() {
    //Checking application start by deep link
    startUri().then(_onRedirected);
    //Checking broadcast stream, if deep link was clicked in opened appication
    stream.receiveBroadcastStream().listen((d) => _onRedirected(d));
  }


  _onRedirected(String uri) {
    // Here can be any uri analysis, checking tokens etc, if it’s necessary
    // Throw deep link URI into the BloC's stream
    stateSink.add(uri);
  }


  @override
  void dispose() {
    _stateController.close();
  }


  Future<String> startUri() async {
    try {
      return platform.invokeMethod('initialLink');
    } on PlatformException catch (e) {
      return "Failed to Invoke: '${e.message}'.";
    }
  }
}

برای ویجت کلی برنامه از StreamBuilder استفاده میکنیم که با توجه به آپدیت شدن State محتویات جدیدی نمایش دهد.

class PocWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    DeepLinkBloc _bloc = Provider.of<DeepLinkBloc>(context);
    return StreamBuilder<String>(
      stream: _bloc.state,
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return Container(
              child: Center(
                  child: Text('No deep link was used  ')));
        } else {
          return Container(
              child: Center(
                  child: Padding(
                      padding: EdgeInsets.all(20.0),
                      child: Text('Redirected: ${snapshot.data}'))));
        }
      },
    );
  }
}

تمام کارهایی که لازم بود را انجام دادیم حالا کافی که وارد آدرس زیر شوید و منتظر شوید تا برنامه اجرا شود.

poc://deeplink.flutter.dev
Flutter deep link

منبع انگلیسی

7 پاسخ به “پیاده سازی Deep link در فلاتر”

  1. Mahdee گفت:

    سلام . عالیه مطالب .
    ولی ای کاش فیلمش رو هم میذاشتید تا کاربردی تر و بهتر درک بشه
    باز هم ممنون از شما و خسته نباشید

  2. احسان گفت:

    سلام وقت بخیر من به یک درگاه پرداخت متصل میشم تمام این کارا رو هم انجام دادم.
    آیا برنامه نویس بک اند باید ی اینتی رو کال کنه تا برگرده به برنامه من.؟؟
    من نمیدونم دقیقا چه اطلاعاتی رو ازش بگیرم تا بعد از پرداخت برگرده به اپ من.
    آیا اگر من ی لینک تستی ست کنم مثلا http://www.google.com و برنامه من هم در بک گراند در حال اجرا باشه
    بعدش روی گوشیم برم این لینک رو با مرورگر باز کنم باید بیاد برنامه من رو باز کنه؟؟
    ممنون میشم اگر راهنماییم کنید.

    • Hesam گفت:

      سلام بله مورد دوم که گفتید صحیح هست بعد از پرداخت کاربر به یک صفحه هدایت میشه معمولا که پرداخت تایید بشه بعد از این قسمت سناریوهای مختلفی میتونه رخ بده مثلا یک دکمه داخل این صفحه قرار داده بشه کاربر با کلیک کردن روی آن به ادرس اینترنتی منتقل بشه که داخل اپ به عنوان deep link تنظیم شده و اپلیکیشن به شکل خودکار باز بشه یا دکمه ای وجود نداشته باشه و بعد از تایید پرداخت ریدایرکت بشه به ادرس مورد نظر تا اپلیکیشن اجرا بشه.

  3. حسين گفت:

    سلام خسته نباشيد وقتتون بخير ببخشيد توي قسمت اندرويد آماده سازی Platform Channels دقيقا بايد چيكار كنيم توي چ فايلي بايد اينا رو بنويسيم چرا اينا سيميكالن ندارن ؟

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

Hesam
06 اکتبر 2020
آموزش فارسی فلاتر
آموزش فارسی flutter