Which package should I use to embed admob in xamarin-forms? - xamarin.forms

I was thinking to use the Xamarin.GooglePlayServices.Ads.Lite package https://www.youtube.com/watch?v=6teJvSCg6UA&t=661s
But I can't find up-to-date instruction for embedding admob in xamarin-forms.
I registered with admob but found instructions only for kotlin and java.
Which package is currently relevant for xamarin-forms? And is there an up-to-date implementation guide?

You could create a control and do that with custom renderer.
Custom control:
public class AdControlView : View
{
}
Custom renderer:
[assembly: ExportRenderer(typeof(AdControlView), typeof(AdViewRenderer))]
namespace App14.Droid
{
public class AdViewRenderer : ViewRenderer<AdControlView, AdView>
{
public AdViewRenderer(Context context) : base(context)
{
}
string adUnitId = string.Empty;
//Note you may want to adjust this, see further down.
AdSize adSize = AdSize.Banner;
AdView adView;
AdView CreateNativeAdControl()
{
if (adView != null)
return adView;
adUnitId = "ca-app-pub-3940256099942544/6300978111"; //you could create you own unit id.
adView = new AdView(Forms.Context);
adView.AdSize = adSize;
adView.AdUnitId = adUnitId;
var adParams = new LinearLayout.LayoutParams(LayoutParams.WrapContent, LayoutParams.WrapContent);
adView.LayoutParameters = adParams;
adView.LoadAd(new AdRequest
.Builder()
.Build());
return adView;
}
protected override void OnElementChanged(ElementChangedEventArgs<AdControlView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
CreateNativeAdControl();
SetNativeControl(adView);
}
}
}
}
Create your own application id and unitid or you could get the test ads on Google Admob.
For more details, please refer to the case i done before.
How to use App ID in Xamarin Visual Studio

Related

Xamarin.Forms Google Services AdMob

I'm trying to implement AdMob in my Xamarin.Forms app (Android version for now). Here is what I have done so far:
Created a custom control, AdViewControl, in my shared project:
public class AdControlView : Xamarin.Forms.View
{
}
In my page in which to show the ad, I added the custom control in xaml:
xmlns:ads="clr-namespace:MyFeelingBuddyTwo.Views"
<ads:AdControlView BackgroundColor="Red"/>
In the Android project (AndroidManifest.xml), within :
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-myappid"/>
<activity android:name="com.google.android.gms.ads.AdActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"/>
In the Android project still, I created an AdViewRenderer:
[assembly: ExportRenderer(typeof(MyFeelingBuddyTwo.Views.AdControlView), typeof(AdViewRenderer))]
namespace MyFeelingBuddyTwo.Droid
{
class AdViewRenderer : ViewRenderer<Views.AdControlView, AdView>
{
string adUnitId = "myadunitid";
AdSize adSize = AdSize.SmartBanner;
AdView adView;
AdView CreateAdView()
{
if (adView != null)
return adView;
adView = new AdView(Forms.Context);
adView.AdSize = adSize;
adView.AdUnitId = adUnitId;
var arParams = new LinearLayout.LayoutParams(LayoutParams.WrapContent, LayoutParams.WrapContent);
adView.LayoutParameters = arParams;
adView.LoadAd(new AdRequest.Builder().Build());
return adView;
}
protected override void OnElementChanged(ElementChangedEventArgs<AdControlView> e)
{
base.OnElementChanged(e);
if(Control == null)
{
CreateAdView();
SetNativeControl(adView);
}
}
}
}
In MainActivity, intialize MobileAds just before loading the app:
MobileAds.Initialize(ApplicationContext, "ca-app-pub-appid");
When I run, I get the red background but no ads are loaded. Any ideas?
In the AdControlView class, I added :
public static readonly BindableProperty AdUnitIdProperty = BindableProperty.Create("AdUnitId", typeof(string), typeof(AdControlView));
public string AdUnitId
{
get { return (string)GetValue(AdUnitIdProperty); }
set { SetValue(AdUnitIdProperty, value); }
}
Now I can see "Test Ad" in the banner placeholder.

How can I create a custom renderer for DatePicker for UWP?

I'm trying to create a custom DatePicker renderer for UWP but I'm getting a compile error.
Trying to get a CalenderDatePicker instead of the normal DataPicker. I am getting the same error whether I try one or the other.
My code is:
CustomControl.cs
namespace myNameSpace.CustomControl
{
public class CustomDatePicker : DatePicker
{
}
}
And my CustomDatePickerRenderer.cs in the UWP folder
[assembly: ExportRenderer(typeof(CustomDatePicker), typeof(CustomDatePickerRenderer))]
namespace myNameSpace.UWP
{
public class CustomDatePickerRenderer : ViewRenderer<DatePicker, Windows.UI.Xaml.Controls.CalendarDatePicker>, ITabStopOnDescendants, IDontGetFocus
{
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
{
base.OnElementChanged(e);
if (Control == null)
{
Windows.UI.Xaml.Controls.CalendarDatePicker datePicker = new Windows.UI.Xaml.Controls.CalendarDatePicker();
SetNativeControl(datePicker);
}
}
}
}
The error I get is:
The type 'Windows.UI.Xaml.Controls.DatePicker' cannot be used as type parameter 'TElement' in the generic type or method 'ViewRenderer<TElement, TNativeElement>'. There is no implicit reference conversion from 'Windows.UI.Xaml.Controls.DatePicker' to 'Xamarin.Forms.View'.
From the documentation I can find this should be ok - is it not possible to create a custom renderer for the DatePicker? Please help.
This might not be a big thing by experiences developers, but I'm thrilled that I got it working - substituting the Xamarin.Forms DataPicker with the UWP CalendarDatePicke - so I'll just post my working solution, if someone else could use it.
Thanks to pinedax for solving my initial problem - which I actually changed to my CustomDatePicker in the end, because this is what is in the documentation from MS.
The last thing I needed was to ensure that Date changes where registered between to two different controls, since they use different events for this.
My code is:
CustomDatePicker.cs
namespace myNameSpace.CustomControl
{
public class CustomDatePicker : DatePicker
{
}
}
CustomDatePickerRenderer.cs in the UWP folder
[assembly: ExportRenderer(typeof(CustomDatePicker), typeof(CustomDatePickerRenderer))]
namespace myNameSpace.UWP
{
public class CustomDatePickerRenderer : ViewRenderer<CustomDatePicker, Windows.UI.Xaml.Controls.CalendarDatePicker>
{
protected override void OnElementChanged(ElementChangedEventArgs<CustomDatePicker> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
// Unsubscribe from event handlers and cleanup any resources
Control.DateChanged -= OnDateChanged;
Element.DateSelected -= OnDateSelected;
}
if (e.NewElement != null)
{
if (Control == null)
{
// Instantiate the native control and assign it to the Control property with
// the SetNativeControl method
if (Control == null)
{
Windows.UI.Xaml.Controls.CalendarDatePicker datePicker = new Windows.UI.Xaml.Controls.CalendarDatePicker();
datePicker.FirstDayOfWeek = Windows.Globalization.DayOfWeek.Monday;
SetNativeControl(datePicker);
}
}
Control.DateChanged += OnDateChanged;
Element.DateSelected += OnDateSelected;
}
}
private void OnDateChanged(CalendarDatePicker sender, CalendarDatePickerDateChangedEventArgs e)
{
DateTimeOffset dto = (DateTimeOffset)e.NewDate;
Element.Date = dto.DateTime;
}
private void OnDateSelected(Object sender, DateChangedEventArgs e)
{
DateTime dt = e.NewDate;
Control.Date = new DateTimeOffset(dt);
}
}
}
And I can now reference my CustomDatePicker (UWP CalendarDatePicker) from my Xamarin.Forms XAML file
<local:CustomDatePicker x:Name="FilterDatePicker" DateSelected="OnDateFilterDateChanged" VerticalOptions="Center"></local:CustomDatePicker>
That's because it's not using the correct DatePicker.
That method expects the Xamarin.Forms.DatePicker but instead it's referencing the Windows.UI.Xaml.Controls.DatePicker.
To fix it either use the long namespace
[assembly: ExportRenderer(typeof(CustomDatePicker), typeof(CustomDatePickerRenderer))]
namespace myNameSpace.UWP
{
public class CustomDatePickerRenderer : ViewRenderer<Xamarin.Forms.DatePicker, Windows.UI.Xaml.Controls.CalendarDatePicker>, ITabStopOnDescendants, IDontGetFocus
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.DatePicker> e)
{
base.OnElementChanged(e);
if (Control == null)
{
Windows.UI.Xaml.Controls.CalendarDatePicker datePicker = new Windows.UI.Xaml.Controls.CalendarDatePicker();
SetNativeControl(datePicker);
}
}
}
}
Or use the using notation at the top of your class to indicate which one to use. Something like
using DatePicker = Xamarin.Forms.DatePicker;
Hope this helps.-

Prism Forms doesn't have OnNavigatingTo anymore. How to run some code before Views's constructor?

Look at the code below. There's two DelegateCommand that are set in Views's constructor:
public DelegateCommand DeletePromotionCommand { get; set; }
public DelegateCommand EditPromotionCommand { get; set; }
public PromotionDetailViewModel(INavigationService navigationService, IPageDialogService pageDialogService)
: base(navigationService, pageDialogService)
{
Title = "Promoção";
DeletePromotionCommand = new DelegateCommand(DeletePromotion, CanDeletePromotion);
EditPromotionCommand = new DelegateCommand(EditPromotion, CanEditPromotion);
}
The CanEditPromotion is called when the EditPromotionCommand is set in the constructor. CanEditPromotion method is shown below:
private bool CanEditPromotion()
{
var userString = Preferences.Get("user", string.Empty);
if (userString == string.Empty)
return false;
var userId = (Guid)JObject.Parse(userString)["id"];
if (userId == Promotion.CreatedBy)
return true;
else
return false;
}
Note that on the 4th sentence I need the Promotion property. This property need to be set before the Views's constructor, so it will be null and, at exactly line, it will break the app.
Before I should use the code below to set Promotion property, but Prism doesn't have OnNavigatingTo method anymore. Promotion info comes from the Page before and is passed as a parameter navigation:
public override async void OnNavigatingTo(INavigationParameters parameters)
{
base.OnNavigatedTo(parameters);
try
{
IsBusy = true;
Promotion = parameters["promotion"] as Promotion;
var marketService = new Service<Market>();
Market = await marketService.GetAsync(Promotion.MarketId);
IsBusy = false;
}
catch (Exception)
{
IsBusy = false;
}
}
When I try to use INavigatingTo at my BaseViewModel, it is show to me a message saying to use IInitialize instead. I tried but the Initialize method is still fired after the View's constructor.
As is indicated in the official release notes for Prism 7.2 OnNavigatingTo was deprecated due after a lot of consideration and feedback from the Prism community. This was in part due to the fact that OnNavigatingTo was expected to run to Initialize your ViewModel prior to the View being pushed onto the Navigation Stack. The issue is that over time its intent was getting lost and people were trying to misuse the API. The only way for us to move forward was to remove the reference to INavigatingAware from INavigationAware which unfortunately creates a soft break in which OnNavigatingTo simply isn't called. In the case where you have a direct reference to INavigatingAware you will get a hard compilation error.
To migrate your code you should use the new initialization API with either IInitialize, IInitializeAsync or IAutoInitialize. Assuming that you simply use IInitialize you'll update your legacy code from:
public void OnNavigatingTo(INavigationParameters parameters)
{
// your code here
}
to the new IInitialize version
public void Initialize(INavigationParameters parameters)
{
// your code here
}
Keep in mind that if you use the Async version of this the long running task will have to complete before the page is pushed thus causing a noticeable delay in navigation. It may often be more desirable therefore to simply use async void to avoid blocking the Navigation.
You can read more in the Prism 7.2 Release Notes here
I resolved this way:
At CanEditPromotion I put a null verification for Promotion property:
private bool CanEditPromotion()
{
var userString = Preferences.Get("user", string.Empty);
if (userString == string.Empty)
return false;
var userId = (Guid)JObject.Parse(userString)["id"];
if (Promotion != null && userId == Promotion.CreatedBy)
return true;
else
return false;
}
And I observe the Promotion property when the EditPromotionCommand is set:
public DelegateCommand DeletePromotionCommand { get; set; }
public DelegateCommand EditPromotionCommand { get; set; }
public PromotionDetailViewModel(INavigationService navigationService, IPageDialogService pageDialogService)
: base(navigationService, pageDialogService)
{
Title = "Promoção";
DeletePromotionCommand = new DelegateCommand(DeletePromotion, CanDeletePromotion)
.ObservesProperty(() => Promotion);
EditPromotionCommand = new DelegateCommand(EditPromotion, CanEditPromotion)
.ObservesProperty(() => Promotion);
}
And I used the OnNavigatedTo method to set Promotion property:
public override async void OnNavigatedTo(INavigationParameters parameters)
{
try
{
IsBusy = true;
Promotion = parameters["promotion"] as Promotion;
var marketService = new Service<Market>();
Market = await marketService.GetAsync(Promotion.MarketId);
IsBusy = false;
}
catch (Exception)
{
IsBusy = false;
}
}

Xamarin.Forms and Plugin.Media: after about 20 photos something crashes

I have a problem with Xamarin.Forms ver. 2.3.4.224 and Plugin.Media ver. 2.6.2. The problem occurs after taking about 20 photos (depends from the device): basically the app crashes without any apparently reason.
If you want to replicate the error, I created a test project for you on GitHub. With my iPad Air or iPad Pro after about 30 photos (video iPad Air - iPad Pro). All devices are iOS ver. 10.3.1 and they have enough space to storage photos.
The app is very simple: you have two buttons one for taking a picture and the other one to pick a photo. If you take photos one after another, after about 20 (32 in an iPad Air) the app crashes. I'm just take photos with the Plugin.Media nothing more.
Any ideas are welcome.
Update
In my project I had a reference to Refractored.MvvmHelpers and I noticed if I remove it, I can take more pictures. I created my BaseViewModel with INotifyPropertyChanged and I noticed I can take more photos.
I created then a new project (you can find it on GitHub under cameratesteasy) without MVVM and there is just the code to take a photo like:
public partial class cameratesteasyPage : ContentPage
{
int count = 0;
public cameratesteasyPage()
{
InitializeComponent();
CrossMedia.Current.Initialize();
}
void UpdateCount()
{
count++;
CountLabel.Text = $"{count} times";
}
async void StartCameraTapped(object sender, System.EventArgs args)
{
using (var file = await CrossMedia.Current.TakePhotoAsync(
new StoreCameraMediaOptions {}))
{
if (file == null)
return;
UpdateCount();
}
}
async void StartCameraTakeTapped(object sender, System.EventArgs args)
{
var file = await CrossMedia.Current.PickPhotoAsync();
if (file == null)
return;
UpdateCount();
}
}
In this case the app shut down after 52 photos. I saved the log for Xcode and you can see it here.
I used Xamarin Profile and the memory level is always low. After about 30 photos, an error occurs in Xamarin Profiler
Finally I could create a Xamarin Profiler file
Also I noticed this kind of error occurs on iPads. The same app in an iPhone is working fine (apparently) or I didn't find up to now the number of photos before crashing.
Update /2
I decided to implement a native function for taking photo.
Interface
public interface ICamera
{
void TakePicture();
}
Implementation
using System;
using cameratest.iOS;
using Foundation;
using UIKit;
using Xamarin.Forms;
[assembly: Xamarin.Forms.Dependency(typeof(Camera_iOS))]
namespace cameratest.iOS
{
public class Camera_iOS : ICamera
{
static UIImagePickerController picker;
static Action<NSDictionary> _callback;
static void Init()
{
if (picker != null)
return;
picker = new UIImagePickerController();
picker.Delegate = new CameraDelegate();
}
class CameraDelegate : UIImagePickerControllerDelegate
{
public override void FinishedPickingMedia(
UIImagePickerController picker, NSDictionary info)
{
var cb = _callback;
_callback = null;
picker.DismissModalViewController(true);
cb(info);
}
}
public static void TakePicture(UIViewController parent,
Action<NSDictionary> callback)
{
Init();
picker.SourceType = UIImagePickerControllerSourceType.Camera;
_callback = callback;
parent.PresentModalViewController(picker, true);
}
public static void SelectPicture(UIViewController parent,
Action<NSDictionary> callback)
{
Init();
picker.SourceType = UIImagePickerControllerSourceType.PhotoLibrary;
_callback = callback;
parent.PresentModalViewController(picker, true);
}
public void TakePicture()
{
var rc = UIApplication.SharedApplication.KeyWindow.RootViewController;
TakePicture(rc, (obj) =>
{
var photo = obj.ValueForKey(
new NSString("UIImagePickerControllerOriginalImage")) as UIImage;
var documentsDirectory =
Environment.GetFolderPath(Environment.SpecialFolder.Personal);
// hardcoded filename, overwritten each time
string jpgFilename = System.IO.Path.Combine(documentsDirectory,
"Photo.jpg");
NSData imgData = photo.AsJPEG();
NSError err = null;
if (imgData.Save(jpgFilename, false, out err))
{
Console.WriteLine("saved as " + jpgFilename);
}
else
{
Console.WriteLine("NOT saved as " +
jpgFilename + " because" + err.LocalizedDescription);
}
});
}
}
}
With this code after about 30 photos, the app crashes. The only difference is with this code I can receive some alert from ReceiveMemoryWarning. If you have an interest, I updated the code on GitHub.

How to programmatically sign a project in c sharp

I am creating projects from a template using DTE. I want the projects to be signed by a particular .snk file. How to do it programmatically??
please help..!!
Thanks,
Girish
What I did is add a new Addin project into my solution and by adding this code:
public void OnConnection(object application, ext_ConnectMode connectMode, objec addInInst, ref Array custom)
{
_applicationObject = (DTE2)application;
_addInInstance = (AddIn)addInInst;
SetSign(_applicationObject);
}
public void SetSign(DTE2 app)
{
Solution solution = app.Solution;
foreach (Project proj in solution.Projects)
{
if (null != proj.Properties && null != proj.Properties.Item("SignAssembly"))
{
Property projProperty = proj.Properties.Item("SignAssembly");
bool signed = (bool)projProperty.Value;
if (!signed)
{
proj.Properties.Item("AssemblyOriginatorKeyFile").Value = #"C:\Projects\ClassLibrary1\Addins\Tools\mykeyfile.pfx";
proj.Properties.Item("SignAssembly").Value = true;
}
proj.Save();
}
}
}

Resources