30 Haziran 2021 Çarşamba

Fazla .net core runtime ve sdk'lerini uninstall etmek

 Sık sık ihtiyacım olduğundan derli toplu burada bulundurmak istediğim tutorial'ım :) 

Eski .net core sdk ve runtime versiyonlarını zaman zaman temizlemek gerekebiliyor. Bu işlem için yardımcı bir paket çıkarmışlar. İsmi dotnet-core-uninstall . Vaat edici bir isim :) Bunu linkteki yönlendirmelere göre yükledim.

Ben genelde tüm major sürümlerin en sonuncusunu tutup gerisini silme yolunu seçiyorum. Bu nedenle önce yüklü olan tüm versiyonları listelemek için 

dotnet --info

komutunu çalıştırdım. Bu bana uzun bir liste verdi. Major versiyonlardan 2.1.x, 2.2.x, 3.1.x, 5.0.x pek çok versiyona sahiptim. Tüm versiyonların en sonuncuları dışındaki hepsini temizlemek için dotnet-core-uninstall paketinin --all-but diye bir komutu var. Bunu kullanmaya karar verdim. Bu sayede "şu şu versiyonlar kalsın gerisini yak" diyebilecektim. Ama gemileri yakmadan önce hangi gemileri yakacağımdan emin olmak için şu komutu çalıştırdım. 

./dotnet-core-uninstall dry-run --all-but 5.0.7 3.1.16 2.2.8 2.1.23 --runtime

Bu komut çıktı olarak hangi runtime versiyonlarını kaldıracağını gösteriyor. Bana şöyle çılgın bir liste verdi. Pislik içindeymiş her yer resmen. 


Baktım benim kaldırmak istemediklerim listede yok o halde kaldırabilirim. Bu işlemi yapabilmek için yetkili bir abiye benzememiz gerekiyor o halde şu komutu yapıştırabiliriz;

sudo ./dotnet-core-uninstall remove --all-but 5.0.7 3.1.16 2.2.8 2.1.23 --runtime

Emin misin? Bak son kararın mı? Parola? gibi doğrulamaları geçtikten sonra tertemiz bir runtime paket depom olmuş olduu... 

Sıra geldi sdk'lere. Çok benzer olduğu için direkt kodları yapıştırıyorum. İlk olarak hangi sdk'lerin kalkacağından emin oluruz;

./dotnet-core-uninstall whatif --all-but 5.0.301 3.1.410 2.2.207 2.1.808 --sdk

Doğrudur. O halde sdk'lerimizle de vedalaşırız; 

sudo ./dotnet-core-uninstall remove --all-but 5.0.301 3.1.410 2.2.207 2.1.808 --sdk

Artık sadece major'larımız var. 

13 Haziran 2020 Cumartesi

Android uygulama kill olduğunda push notification almama sorununun çözümü


Bir süredir sıklıkla Xamarin.Forms uygulamamda push notification'lar ile cebelleşmekteydim. Bu seferki "mono laneti" değil, tamamen bilgisizlik. :D Böyle böyle öğreniyoruz işte güzel de oluyor. Şimdi sıra unutmamak için bloguma not etmekte. (ÖVUN : Unutmama ve Öğrenme Notu :P)

Kısaca neden her şey sorunsuz çalışırken notificationlar ile ilgili sorun yaşamaya başladığımdan bahsedeyim; çünkü düz notificationlardan sıkılmıştım ve heyecan arıyordum. Notification'ıma butonlar resimler sesler fln eklemek istedim :) Bunu da AppCenter'ın simple push notification'ı ile yapmak mümkün değil. Yani notification ortamımı değiştirip Firebase'e geçiş yaptıım.. Bunu nasıl yaptığımla ilgili de bloguma ÖVUN ekleyeceğim ama ilk olarak beni 2 gün boyunca uğraştıran uygulama kill olduğunda notification gelmeme sorununun çözümünü paylaşayım.

iOS'u implemente ettik sıkıntı yok, ama Android'e gelince uygulama arka planda olmadığı müddetçe notification hiç gelmiyor gibi davranıyordu.
Sorun düz notification atmıyor oluşumdu. Yani içinde karmaşık bir data bulunduran ve notification'ı alıp işleyip butonlu resimli bir hale getirmem gerekliliği notification alamıyor oluşumun nedeniydi.



Yukarıdaki görüntü çoğu yazılımcı için tanıdıktır. Araştırma, tab tab tab, örnek projeler, stackoverflowlar. Gerçekten gocunmuyorum severim workaround dolaşmayı. Ama bu kadar mı çözümsüz çözümler sunulabilir, mümkün değil diyenlerle, ama o zaman x-y uygulaması nasıl yapıyor diyenlerin birbirine girmesi. Garip garip "hackvari" çözümler vs.. Xamarin forumu zaten komple acziyet doluydu. Neyse :D 

Sağlıklı çözüme araştırmalarımdan ulaşamadım maalesef. Ama meğer araştırmayı bilmiyormuşum. Uzmanımın yol göstermesiyle notification gelme olayında başarılı olan bir uygulamanın apk'sını indirip biraz karıştırdık ve çözüme bu şekilde ulaşmış olduk.

Çözüm manifest dosyasına birkaç ayar eklemek kadar basitti aslında. Anahtar kelimemiz; 

android:stopWithTask="false"

Peki bu ayarı nasıl ekliyoruz? Manifest'i source code editor ile açıp application taglarının içine aşağıdaki komutu yapıştırıyoruz; 

<service android:name="com.mybundle.myapp.MyBackgroundMessagingService" android:exported="false" android:stopWithTask="false">
     <intent-filter>
          <action android:name="com.google.firebase.MESSAGING_EVENT" />
          <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
     </intent-filter>
</service>

Tahmin edebileceğiniz gibi "com.mybundle.myapp.MyBackgroundMessagingService" kısmına kendi uygulamanızı ve servisinizi yazmanız gerekiyor.

Bir de direkt olarak etkisi var mıdır emin olmamakla birlikte şu permission'ları da ekledim;

<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.VIBRATE" />

Artık application'ızı kill edip edip içinde datası olan da olmayan da yakışıklı notification'larınızın keyfini yaşayıp yaşatabilirsiniz. 


7 Ağustos 2019 Çarşamba

ngrok tek process'te birden fazla tünelleme yapmak


Bir süredir ngrok kullanarak mobil geliştirme yapıyorum. ngrok kullanmam gereken 2 adet backend uygulaması var ve şimdiye kadar tek tek ngrok komutlarını yazıp çalıştırıyordum, ngrok ise pro sürümünde aynı anda 2 process'ten fazlasına izin vermiyor. Yani ben 2 process'i de kaplıyordum ve ngrok pro'yu beraber kullandığım uzmanım da umurumda olmuyordu :D :D .

Sonra bu problem ile ilgili uzmanımla problem kabul seansları yaptık ve problemi kabullenebildim :P

Tedavi süreci ise şöyle oldu;

vs code'da ngrok yml dosyasını açtık.
code ~/.ngrok2/ngrok.yml


İki process'imi de buraya şu şekıl tanımladım;

authtoken: 3s4PZenginlerinKullandığıNgrok'tanJGxwK
region: eu
console_ui: true
tunnels:
  birinci_backend:
   proto: http
   addr: 4033
   subdomain: birinci_backend
  ikinci_backend:
   proto: http
   addr: 4034
   subdomain: ikinci_backend


Artık 
ngrok start --all
dediğimde iki backend'im de yayında ve tek process kullanıyorlar.


Bonus;
fish'e de kısayol ekleyelim.
code ~/.config/fish/config.fish

...
alias ngup="ngrok start --all"
...

Artık fish'e ngup yazıp iki tünellememi de kullanıp ikinci process'i uzmanıma bırakıyorum. Böyle de iyi bir insanım. :p :P :p :P


6 Nisan 2019 Cumartesi

Firebase Cloud Functions Parsing error



Geliştirdiğim mobil uygulamanın kendine ait bir API'ı yok şuanda maalesef, başka bir uygulamanın API'ını kullanıyorum. Kendi API'ım da olacak inş ancak o zamana kadar versiyon güncellemelerini kontrol edebileceğim ufak, şirin bir metod'a ihtiyacım vardı.

Ne yapsam diye düşünürken çok yakın zamanda şirket içi eğitimde öğrendiğimiz azure'un serverless'inin function'larını kullanabilirim diye düşündüm. Sonra hali hazırda Firebase kullandığım için Firebase'in functions'ını inceledim ve direkt oraya yazayım diye karar verdim.. :)

Az yazdım, uz yazdım, dere tepe bir türlü odaklanamayarak ve uzun uzun yazdım ama sonunda bitti ve deploy aşamasına gelebildiiim :) 

Ama derin bir nefes alarak firebase deploy --only functions komutumu çalıştırdığımda başından beri yakamda olan mono lanetini yine başımda buldum. Şöyle bir hata vermekteydi;

firebase deploy --only functions

=== Deploying to 'my-api'...

i  deploying functions
Running command: npm --prefix "$RESOURCE_DIR" run lint

> functions@ lint /Users/monolara/Desktop/git/MyAPI/functions
> eslint .


/Users/monolara/Desktop/git/MyAPI/functions/index.js
  16:36  error  Parsing error: Unexpected token =>

✖ 1 problem (1 error, 0 warnings)

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! functions@ lint: `eslint .`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the functions@ lint script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/monolara/.npm/_logs/2019-04-06T13_28_06_446Z-debug.log

Error: functions predeploy error: Command terminated with non-zero exit code1

Having trouble? Try firebase deploy --help

Kızdığı şey async metodlarımdı. Ama nasıl olurdu, quickstart örneklerinde dahi async yazmışlardı ve "localimde çalışıyor"du.

Araştırdım. Ve sorunun firebase-functions'ın benim için oluşturduğu default projede ecmaVersion'ın 6 olarak geldiğini ve bu versiyonda async metodların olmadığını öğrendim. Kısaca çözüm;

.eslintrc.json dosyamızdaki ecmaVersion değerini 2017 ile değiştirmekte. Yani şöyle;
"parserOptions": { // Required for certain syntax usages "ecmaVersion": 2017 },

Bir de package.json dosyamıza şunu da eklemek gerek;
"engines": { "node": "8" },

Bir mono lanetini daha böyle aşıp güzel güzel deployumuzu yaptık. Darısı diğer lanetlere :)

10 Ekim 2018 Çarşamba

Adding custom gestures to Xamarin.Forms VisualElements with Renderer


Tek yapmak istediğim label'ıma uzun basılı tuttuktan sonra içindeki text'in kopyalanmasıydı. Haliyle gesture'lara baktım ancak xamarin.forms içinde hali hazırda "longtap" gibi bir gesturerecognizer olmadığını gördüm..

Haliyle ben de "LAYN!" deyip özel, uzun basılabiliritesi olan bir label yaptım. :) Güzel örneği bulunca hepsini ekleyesim de geldi ama sonra dedim boşver mono, zaten örnek var starla geç.
Hemen unutmadan kaynağı ekleyeyim;


Forms;
using System;
using Xamarin.Forms;

namespace GestureRendererSample
{
    public class MyLabel : Label
    {
        public MyLabel()
        {
        }
        public Action OnLongTap { get; set; }
    }
}

Android;

LabelRenderer;
using System;
using Android.Content;
using Android.Views;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(MyLabel), typeof(MyLabelRenderer))]
namespace GestureRendererSample.Droid
{
    public class MyLabelRenderer : LabelRenderer
    {
        private readonly GestureListener _listener;
        private readonly GestureDetector _detector;

        public MALabelRenderer(Context context) : base(context)
        {
            _listener = new GestureListener();
            _detector = new GestureDetector(context, _listener);
            #region LongPressedtoLabel
            //Bu kısım biraz eksik kaldı maalesef acele iş fln durumları. En hızlı çözümü messaging center ile buldum, tabii ki geçici :)
            MessagingCenter.Unsubscribe<string>(string.Empty, "LongPressedtoLabel");
            MessagingCenter.Subscribe<string>(string.Empty, "LongPressedtoLabel",
            (sender) =>
            {
                try
                {
                    var control = ((MALabel)this.Element);
                    if (control?.OnLongTap != null)
                    {
                        control.OnLongTap();
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.LogError(ex);
                }
            });

            #endregion
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement == null)
            {
                this.GenericMotion -= HandleGenericMotion;
                this.Touch -= HandleTouch;
            }

            if (e.OldElement == null)
            {
                this.GenericMotion += HandleGenericMotion;
                this.Touch += HandleTouch;
            }
        }

        void HandleTouch(object sender, TouchEventArgs e)
        {
            _detector.OnTouchEvent(e.Event);
        }

        void HandleGenericMotion(object sender, GenericMotionEventArgs e)
        {
            _detector.OnTouchEvent(e.Event);
        }
    }
}


GestureListener;
using System;
using Android.Views;

namespace GestureRendererSample.Droid
{
public class GestureListener : GestureDetector.SimpleOnGestureListener
{
public override void OnLongPress(MotionEvent e)
{
MessagingCenter.Send(string.Empty, "LongPressedtoLabel");
base.OnLongPress(e);
}

public override bool OnDoubleTap(MotionEvent e)
{
return base.OnDoubleTap(e);
}

public override bool OnDoubleTapEvent(MotionEvent e)
{
return base.OnDoubleTapEvent(e);
}

public override bool OnSingleTapUp(MotionEvent e)
{
return base.OnSingleTapUp(e);
}

public override bool OnDown(MotionEvent e)
{
return base.OnDown(e);
}

public override bool OnFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
{
return base.OnFling(e1, e2, velocityX, velocityY);
}

public override bool OnScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
{
return base.OnScroll(e1, e2, distanceX, distanceY);
}

public override void OnShowPress(MotionEvent e)
{
base.OnShowPress(e);
}

public override bool OnSingleTapConfirmed(MotionEvent e)
{
return base.OnSingleTapConfirmed(e);
}
}
}


iOS;
using System;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(MyLabel), typeof(MyLabelRenderer))]
namespace GestureRendererSample.iOS
{
    public class MyLabelRenderer : LabelRenderer
    {
        UILongPressGestureRecognizer longPressGestureRecognizer;

//UIPinchGestureRecognizer pinchGestureRecognizer;
//UIPanGestureRecognizer panGestureRecognizer;
//UISwipeGestureRecognizer swipeGestureRecognizer;
//UIRotationGestureRecognizer rotationGestureRecognizer;

        public MyLabelRenderer()
        {
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
        {
            base.OnElementChanged(e);

            longPressGestureRecognizer = new UILongPressGestureRecognizer(() => {
                var control = ((MyLabel)this.Element);
                if (control?.OnLongTap != null)
                {
                    control.OnLongTap();
                }
            });

//pinchGestureRecognizer = new UIPinchGestureRecognizer(() => Console.WriteLine("Pinch"));
//panGestureRecognizer = new UIPanGestureRecognizer(() => Console.WriteLine("Pan"));
//swipeGestureRecognizer = new UISwipeGestureRecognizer(() => Console.WriteLine("Swipe"));
//rotationGestureRecognizer = new UIRotationGestureRecognizer(() => Console.WriteLine("Rotation"));

            if (e.NewElement == null)
            {
                if (longPressGestureRecognizer != null)
                {
                    this.RemoveGestureRecognizer(longPressGestureRecognizer);
                }

//if (pinchGestureRecognizer != null)
//{
// this.RemoveGestureRecognizer(pinchGestureRecognizer);
//}
//if (panGestureRecognizer != null)
//{
// this.RemoveGestureRecognizer(panGestureRecognizer);
//}
//if (swipeGestureRecognizer != null)
//{
// this.RemoveGestureRecognizer(swipeGestureRecognizer);
//}
//if (rotationGestureRecognizer != null)
//{
// this.RemoveGestureRecognizer(rotationGestureRecognizer);
//}
            }

            if (e.OldElement == null)
            {
                this.AddGestureRecognizer(longPressGestureRecognizer);

//this.AddGestureRecognizer(pinchGestureRecognizer);
//this.AddGestureRecognizer(panGestureRecognizer);
//this.AddGestureRecognizer(swipeGestureRecognizer);
//this.AddGestureRecognizer(rotationGestureRecognizer);
            }
        }
    }
}


Bu da buracıkta duruversin gari