DependencyService trong Xamarin

I. Giới thiệu: Khi lập trình Xamarin Forms, đôi lúc bạn sẽ gặp trường hợp một số chức năng của native platform không đưọc implement trong Forms API. Trong những trường hợp này, DependencyService sẽ giúp bạn truy cập và sử dụng các chức năng của navite Xamarin cho từng platform. Ví dụ: Bạn muốn truy cập chức năng GPS, mỗi platform Android hay iOS sẽ có chức năng GPS được implement khác nhau. Trong trường hợp này, sử dụng DependencyService sẽ cho bạn khả năng truy cập vào GPS native function của mỗi platform thông qua shared code của Portable Class Library (PCL).

II. DependencyService hoạt động thế nào? Trong Xamarin Forms, để sử dụng DependencyService cần 3 thành phần:

  • Interface - Chức năng phải định nghĩa bằng interface trong shared code.
  • Implementation Per Platform - Thêm các class implement chức năng của interface vào từng platform project.
  • Registration - Mỗi class implement phải đăng kí với DependencyService thông qua meta attribute. Việc đăng kí sẽ enable DependencyService để tìm kiếm những class implement và cung cấp nó thay cho interface trong run time.
  • Call to DependencyService - Share code sẽ gọi DependencyService để implement interface.

Một điểm quan trọng cần phải ghi nhớ ở đây là phải implement tất cả các method của interface trong từng platform nếu không sẽ fail khi chạy runtime.

Sơ đồ application khi sử dụng DependencyService:

Interface Interface sẽ định nghĩa cách bạn tương tác với function của từng platformm. Chúng ta hãy thử thiết kế một interface chuyển text thành giọng nói như sau:

public interface ITextToSpeech {
    void Speak ( string text );  //các thành phần trong interface mặc định là public
}

Code interface trong shared code sẽ cho phép Xamarin.Forms app truy cập vào speech API của mỗi platform. Note: Các class implement interface phải có hàm khởi tại không chứa tham số khi sử dụng DependencyService.

Implement cho từng platform Khi đã thiết kế được một interface phù hợp, trong mỗi platform sẽ implement interface đó. Hãy xem thử Implement trong iOS xem thế nào?

[assembly: Dependency(typeof(TextToSpeechImplementation))]
namespace DependencyServiceSample.iOS
{
    public class TextToSpeechImplementation : ITextToSpeech
    {
        public TextToSpeechImplementation() { }

        public void Speak(string text)
        {
            var speechSynthesizer = new AVSpeechSynthesizer();
            var speechUtterance = new AVSpeechUtterance(text)
            {
                Rate = AVSpeechUtterance.MaximumSpeechRate / 4,
                Voice = AVSpeechSynthesisVoice.FromLanguage("en-US"),
                Volume = 0.5f,
                PitchMultiplier = 1.0f
            };

            speechSynthesizer.SpeakUtterance(speechUtterance);
        }
    }
}

Thuộc tính [assembly] đăng ký class như là một implement của ItextToSpeech interface, có nghĩa là DependencyService.Get<ITextToSpeech>() có thể sử dụng trong shared code để tạo một thể hiện cho nó. Thế còn implement trong Android thì sao?

[assembly: Dependency(typeof(TextToSpeechImplementation))]
namespace DependencyServiceSample.Droid
{

    public class TextToSpeechImplementation : Java.Lang.Object, ITextToSpeech, TextToSpeech.IOnInitListener
    {
        TextToSpeech speaker;
        string toSpeak;

        public void Speak(string text)
        {
            toSpeak = text;
            if (speaker == null)
            {
                speaker = new TextToSpeech(Forms.Context, this);
            }
            else
            {
                speaker.Speak(toSpeak, QueueMode.Flush, null, null);
            }
        }

        public void OnInit(OperationResult status)
        {
            if (status.Equals(OperationResult.Success))
            {
                speaker.Speak(toSpeak, QueueMode.Flush, null, null);
            }
        }
    }
}

Android code hơi phức tạp hơn bên iOS một chút: để implement IonInitListener interface trong Android, class implement ITextToSpeech phải kế thừa từ Java.Lang.Object. Xamarin.Forms cũng cung cấp Forms.Context object là một thể hiện của context hiện tại trong Android, nhiều Android SDK vẫn yêu cầu điều này. Giờ là lúc Implement trong Share Code để truy cập vào text-to-speech interface. Hãy tạo 1 view đơn giản với button trigger chức năng speech. DependencyService được sử dụng để lấy instance của ItextToSpeech interface . Trong runtime instance này sẽ được implement và được truy cập đầy đủ chức năng của native SDK.

public MainPage ()
{
    var speak = new Button {
        Text = "Hello, Forms !",
        VerticalOptions = LayoutOptions.CenterAndExpand,
        HorizontalOptions = LayoutOptions.CenterAndExpand,
    };
    speak.Clicked += (sender, e) => {
        DependencyService.Get<ITextToSpeech>().Speak("Hello from Xamarin Forms");
    };
    Content = speak;
}

Chạy application trên iOS, Android và ấn button sẽ cho ra kết quả "Hello from Xamarin Forms" 😄

III. Cấu trúc Solution

Vậy DependencyService sử dụng khi chúng ta phải implement function mà Xamarin.Forms API chưa định nghĩa sẵn bằng việc tạo interface trong shared code và implement trong từng platform. Việc này sẽ yêu cầu một số kiến thức từ native tuy nhiên cũng không quá khó đối với những người đã làm native khi chuyển sang Xamarin. Cảm ơn mọi người đã đọc bài này của mình 😄


All Rights Reserved