Как запустить приложение Xamarin.Forms на устройстве Android Wear

Как запустить Xamarin.Forms.Platform.Android.FormsApplicationActivity на устройстве Android Wear? Вызов base.OnCreate(bundle) внутри метода onCreate моего класса всегда вызывает исключение RuntimeException «Вы не можете использовать неопределенный прогресс на часах».

Вот мой код:

namespace Test
{
    [Activity (Label = "Temp.Droid", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
    {
        protected override void OnCreate (Bundle bundle)
        {
            base.OnCreate (bundle);

            global::Xamarin.Forms.Forms.Init (this, bundle);

            LoadApplication (new App ());
        }
    }
}

Реализация App не должна иметь значения, так как исключение уже вызывается при вызове супер onCreate, а не при вызове LoadApplication (new App ()) для загрузки приложения. Однако это базовая реализация, созданная мастером проекта для мобильного приложения Xamarin.


person Community    schedule 17.04.2015    source источник
comment
Действительно ли оно настроено как приложение для ношения или это PCL #, ссылающийся на элементы, которые недоступны в износе? Возможно, следуйте инструкциям здесь blog.xamarin.com/tips- для вашего первого приложения для Android   -  person ClintL    schedule 17.04.2015


Ответы (2)


Несмотря на ответ Джеймса Монтеманьо, я обнаружил, что можно синхронизировать данные в Xamarin Forms. Я использовал метод Vincent Maverick и включил его в Xamarin Forms. Прежде всего убедитесь, что у вас установлен правильный Android SDK (Учебное пособие по Android Wear — подробное введение). Если у вас есть стандартное приложение, рекомендуется создать приложение Wear в отдельном кросс-платформенном приложении Xamarin Forms. Это потому, что размеры Wear отличаются от размеров телефона.

Как в приложении Wear, так и в приложении для телефона щелкните правой кнопкой мыши ссылки вашего проекта Android и выберите УПРАВЛЕНИЕ ПАКЕТАМИ NUGET. Найдите износ и выберите
Xamarin.GooglePlayServices.Wearable версии 29.0.0 (более поздние версии вызывают проблемы).

введите здесь описание изображения

Нажмите «Свойства» вашего проекта Android в обоих приложениях. Убедитесь, что пространство имен по умолчанию (вкладка «Приложение») и имя пакета (вкладка «Манифест Android») совпадают. Также убедитесь, что в имени пакета нет заглавных букв, это вызовет проблемы при выпуске вашего приложения в магазин Android. Измените значение «Компилировать с использованием версии Android» на «Уровень API 21 (поддержка Xamarin.Android v5.0).

введите здесь описание изображения

В вашем Android MainActivity обоих проектов добавьте использование

using Android.Gms.Wearable;
using Android.Gms.Common.Apis;
using Android.Support.V4.Content;

Затем измените MainActivity обоих приложений на следующее:

public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, IDataApiDataListener, IMessageApiMessageListener
{
    private static GoogleApiClient client;
    const string _syncPath = "/MySyncPath/Data";
    static string device = "Watch";
    static string text= "";

    protected override void OnCreate(Bundle bundle)
    {
        TabLayoutResource = Resource.Layout.Tabbar;
        ToolbarResource = Resource.Layout.Toolbar;

        base.OnCreate(bundle);

        global::Xamarin.Forms.Forms.Init(this, bundle);
        LoadApplication(new App());

        client = new GoogleApiClient.Builder(this)
              .AddApi(WearableClass.API)
              .Build();
        IntentFilter filter = new IntentFilter(Intent.ActionSend);
        MessageReciever receiver = new MessageReciever(this);
        LocalBroadcastManager.GetInstance(this).RegisterReceiver(receiver, filter);
    }

    internal class MessageReciever : BroadcastReceiver
    {
        MainActivity _main;
        public MessageReciever(MainActivity owner) { this._main = owner; }
        public override void OnReceive(Context context, Intent intent)
        {
            _main.ProcessMessage(intent);
        }

    }

    public void OnDataChanged(DataEventBuffer dataEvents)
    {
        var dataEvent = Enumerable.Range(0, dataEvents.Count)
                                  .Select(i => dataEvents.Get(i).JavaCast<IDataEvent>())
                                  .FirstOrDefault(x => x.Type == DataEvent.TypeChanged && x.DataItem.Uri.Path.Equals(_syncPath));
        if (dataEvent == null)
            return;
        //do stuffs here
    }

    public override void OnBackPressed()
    {
           base.OnBackPressed();
    }

    protected override void OnStart()
    {
        base.OnStart();
        Android.Util.Log.Info("WearIntegration", "Received Message");

        client.Connect();
    }

    public void OnConnected(Bundle p0)
    {
        WearableClass.DataApi.AddListener(client, this);
    }

    public void OnConnectionSuspended(int reason)
    {
        Android.Util.Log.Error("GMSonnection suspended " + reason, "");
        WearableClass.DataApi.RemoveListener(client, this);
    }

    public void OnConnectionFailed(Android.Gms.Common.ConnectionResult result)
    {
        Android.Util.Log.Error("GMSonnection failed " + result.ErrorCode, "");
    }


    protected override void OnStop()
    {
        base.OnStop();
        client.Disconnect();
    }

    public void OnMessageReceived(IMessageEvent messageEvent)
    {
        if (messageEvent.Path.Equals(_syncPath))
        {
            var msg = System.Text.Encoding.UTF8.GetString(messageEvent.GetData());

            this.RunOnUiThread(() =>
                Android.Widget.Toast.MakeText(this, msg, ToastLength.Long).Show());
        }
    }

    public void ProcessMessage(Intent intent) 
    {
        if (intent.GetStringExtra("Device") != device)
        {
            text = intent.GetStringExtra("WearMessage");
            //do stuffs here

        }
    }

    public void SendData() {
        try {
            var request = PutDataMapRequest.Create(_syncPath);
            var map = request.DataMap;
            map.PutString("Device", device);
            map.PutString("Message", "Xamarin Forms says Hello from Wearable!");
            map.PutLong("UpdatedAt", DateTime.UtcNow.Ticks);
            WearableClass.DataApi.PutDataItem(_client, request.AsPutDataRequest());
        }
        finally {
            _client.Disconnect();
        }

}

В приложении «Телефон» измените статическое строковое устройство на «Телефон» и измените текст сообщения, если хотите:

    static string device = "Phone";

            map.PutString("Message", "Xamarin Forms says Hello from Phone!");

Затем добавьте класс WearService в оба ваших проекта Android, добавьте те же способы использования, что и в MAinActivity, и измените Wearservice следующим образом:

[Service]
[IntentFilter(new[] { "com.google.android.gms.wearable.BIND_LISTENER" })]
public class WearService : WearableListenerService
{
    const string _syncPath = "/KorfballTimer/Data";
    GoogleApiClient _client;

    public override void OnCreate()
    {
        base.OnCreate();
        _client = new GoogleApiClient.Builder(this.ApplicationContext)
                .AddApi(WearableClass.API)
                .Build();

        _client.Connect();

        Android.Util.Log.Info("WearIntegrationreated", "");
    }

    public override void OnDataChanged(DataEventBuffer dataEvents) 
    {
        var dataEvent = Enumerable.Range(0, dataEvents.Count)
                                  .Select(i => dataEvents.Get(i).JavaCast<IDataEvent)
                                  .FirstOrDefault(x => x.Type == DataEvent.TypeChanged && x.DataItem.Uri.Path.Equals(_syncPath));
        if (dataEvent == null)
            return;

        //get data from wearable
        var dataMapItem = DataMapItem.FromDataItem(dataEvent.DataItem);
        var map = dataMapItem.DataMap;
        string message = dataMapItem.DataMap.GetString("Message");

        Intent intent = new Intent();
        intent.SetAction(Intent.ActionSend);
        intent.PutExtra("WearMessage", message);
        intent.PutExtra("Device", map.GetString("Device"));
        LocalBroadcastManager.GetInstance(this).SendBroadcast(intent);
    }
}

И, наконец, добавьте метаданные в AndroidManifest.xml под элементом:

    <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />

Если вам не нужны проекты IOS и Windows в приложении Wear, просто удалите их. Теперь вы можете создать приложение Wear в Xamarin Forms точно так же, как и приложение для телефона. Удачного кодирования.

person Kees Dapperens    schedule 26.11.2017
comment
При использовании VS2017 Community версии 15.5.1 это решение не будет работать. В VS 2017 версии 15.5.2 это снова будет работать с использованием последней версии Xamarin.Forms (v2.5.0.121934) и версии Xamarin.GooglePlayservice.Wearable v42.1001.0. - person Kees Dapperens; 19.12.2017

Вы не будете запускать приложение Xamarin.Forms на носимом устройстве. Вам потребуется создать новое приложение Android Wear в родном Xamarin.Android. Носимые приложения используют специальную тему, специальные элементы управления и специальные API. Хорошим примером для рассмотрения является то, как я сделал Hanselman.Forms, которое является основным приложением Xamarin.Forms, но также связано с приложением Android Wear: https://github.com/jamesmontemagno/Hanselman.Forms

person JamesMontemagno    schedule 18.04.2015
comment
Это все еще актуально сегодня? Поскольку я только что протестировал свое приложение XF на носимом эмуляторе без изменений, оно работает нормально, за исключением того, что пользовательский интерфейс не оптимизирован для часов. - person Emil; 11.04.2018