Xamarin.Forms Google Services AdMob - xamarin.forms

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.

Related

Which package should I use to embed admob in 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

Xamarin Forms: ios:Page.UseSafeArea is not working for all the children in CarouselPage

I have a CarouselPage having 4 children. For every pages I have added ios:Page.UseSafeArea, but SafeArea property is working only for first 2 pages and for the remaining 2 pages the safe area feature is not working. My XF version is 4.7.0.1080 (latest one).
I found the same issue on Github, is there any solution for this issue?
Create a custom renderer to wrote your own safeAreaInsets and then assign it to Page.Padding. Here use a 200ms delay to wait the initialization of UIApplication.SharedApplication.KeyWindow.
[assembly: ExportRenderer(typeof(CustomPage), typeof(CustomPageRenderer))]
namespace App19F_8.iOS
{
public class CustomPageRenderer : PageRenderer
{
public CustomPageRenderer()
{
}
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
var inset = new Thickness();
Device.StartTimer(new TimeSpan(200), () =>
{
Device.BeginInvokeOnMainThread(() =>
{
if (UIApplication.SharedApplication.KeyWindow != null)
{
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
var safeAreaInsets = UIApplication.SharedApplication.KeyWindow.SafeAreaInsets;
inset.Top = safeAreaInsets.Top;
inset.Bottom = safeAreaInsets.Bottom;
inset.Left = safeAreaInsets.Left;
inset.Right = safeAreaInsets.Right;
}
}
ContentPage page = e.NewElement as ContentPage;
page.Padding = inset;
});
return false;
});
}
}
}
}
In your Xamarin.forms project, make the page in your CarouselPage inherits from CustomPage.

Is there a way to use the camera functions in Xamarin Forms without downloading any extra NuGet Packages?

I am currently building a project which allows the user to take a photo of something and use that photo. I was wondering if there were any other methods out there that does not require me to download any Plugins or NuGet Packages?
You need to create a ICameraPickerService in Xamarin Forms :
public interface IPhotoPickerService
{
Task<byte[]> GetImageStreamAsync();
}
In iOS , create the CameraPickerService :
[assembly: Dependency(typeof(CameraPickerService))]
namespace DependencyServiceDemos.iOS
{
public class CameraPickerService: ICameraPickerService
{
TaskCompletionSource<byte[]> taskCompletionSource;
UIImagePickerController imagePicker;
public Task<byte[]> GetImageStreamAsync()
{
// Create and define UIImagePickerController
imagePicker = new UIImagePickerController
{
SourceType = UIImagePickerControllerSourceType.Camera,
MediaTypes = UIImagePickerController.AvailableMediaTypes(UIImagePickerControllerSourceType.Camera)
};
// Set event handlers
imagePicker.FinishedPickingMedia += OnImagePickerFinishedPickingMedia;
imagePicker.Canceled += OnImagePickerCancelled;
// Present UIImagePickerController;
UIWindow window = UIApplication.SharedApplication.KeyWindow;
var viewController = window.RootViewController;
viewController.PresentModalViewController(imagePicker, true);
// Return Task object
taskCompletionSource = new TaskCompletionSource<byte[]>();
return taskCompletionSource.Task;
}
void OnImagePickerFinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs args)
{
UIImage image = args.EditedImage ?? args.OriginalImage;
if (image != null)
{
// Convert UIImage to .NET Stream object
NSData data;
if (args.ReferenceUrl.PathExtension.Equals("PNG") || args.ReferenceUrl.PathExtension.Equals("png"))
{
data = image.AsPNG();
}
else
{
data = image.AsJPEG(1);
}
Stream stream = data.AsStream();
UnregisterEventHandlers();
// Set the Stream as the completion of the Task
taskCompletionSource.SetResult(data.ToArray());
}
else
{
UnregisterEventHandlers();
taskCompletionSource.SetResult(null);
}
imagePicker.DismissModalViewController(true);
}
void OnImagePickerCancelled(object sender, EventArgs args)
{
UnregisterEventHandlers();
taskCompletionSource.SetResult(null);
imagePicker.DismissModalViewController(true);
}
void UnregisterEventHandlers()
{
imagePicker.FinishedPickingMedia -= OnImagePickerFinishedPickingMedia;
imagePicker.Canceled -= OnImagePickerCancelled;
}
}
}
Not forgetting to add permission in Info.plist :
<key>NSCameraUsageDescription</key>
<string>Use Camera</string>
In addition , iOS need to run in a physical device.
In Android , create the CameraPickerService :
[assembly: Dependency(typeof(CameraPickerService))]
namespace DependencyServiceDemos.Droid
{
public class CameraPickerService : ICameraPickerService
{
public Task<byte[]> GetImageStreamAsync()
{
// Define the Intent for getting images
Intent getImageByCamera = new Intent("android.media.action.IMAGE_CAPTURE");
// Start the camera (resumes in MainActivity.cs)
MainActivity.Instance.StartActivityForResult(
getImageByCamera,
MainActivity.PickImageId);
// Save the TaskCompletionSource object as a MainActivity property
MainActivity.Instance.PickImageTaskCompletionSource = new TaskCompletionSource<byte[]>();
// Return Task object
return MainActivity.Instance.PickImageTaskCompletionSource.Task;
}
}
}
Adding permission in AndroidMainfest.xml :
<uses-permission android:name= "android.permission.CAMERA" />
<uses-permission android:name= "android.permission.WRITE_EXTERNAL_STORAGE" />
Get Image data in MainActivity :
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
internal static MainActivity Instance { get; private set; }
public int CAMERA_JAVA_REQUEST_CODE = 1;
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Instance = this;
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
LoadApplication(new App());
DependencyService.Register<ITextToSpeechService, TextToSpeechService>();
}
// Field, property, and method for Picture Picker
public static readonly int PickImageId = 1000;
public TaskCompletionSource<byte[]> PickImageTaskCompletionSource { set; get; }
protected override void OnActivityResult(int requestCode, Result resultCode, Intent intent)
{
base.OnActivityResult(requestCode, resultCode, intent);
if (requestCode == PickImageId)
{
if ((resultCode == Result.Ok) && (intent != null))
{
Bundle bundle = intent.Extras;
Bitmap bitmap = (Bitmap)bundle.Get("data");
//// Set the Stream as the completion of the Task
MemoryStream memoryStream = new MemoryStream();
bitmap.Compress(Bitmap.CompressFormat.Jpeg, 50, memoryStream);
PickImageTaskCompletionSource.SetResult(memoryStream.ToArray());
}
else
{
PickImageTaskCompletionSource.SetResult(null);
}
}
}
}
Finally , show image in ContentPage of Forms :
async void OnPickPhotoButtonClicked(object sender, EventArgs e)
{
(sender as Button).IsEnabled = false;
byte[] data = await DependencyService.Get<IPhotoPickerService>().GetImageStreamAsync();
MemoryStream stream = new MemoryStream(data);
if (stream != null)
{
image.Source = ImageSource.FromStream(() => stream) ;
}
(sender as Button).IsEnabled = true;
}
The effect :
Note : If want to pick a Photo from the Picture Library, you can have a look at this official document .

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.-

Intercept global event Xamarin Forms

In MainActivity.cs I have this method
public override bool OnKeyUp(Keycode keyCode, KeyEvent e)
{
if (keyCode.ToString().Equals("F1"))
{
App.Left = true;
App.Right = false;
}
else if (keyCode.ToString().Equals("F2"))
{
App.Left = false;
App.Right = true;
}
else
{
App.Left = false;
App.Right = false;
}
return base.OnKeyUp(keyCode, e);
}
In my Page class, how can I constantly check whether left or right are true and in case trigger an event?
Create a plugin using Dependency Service and your shared interface should look like this:
public interface IKeyEvent
{
event Action<KeyResult> OnKeyEvent;
}
public enum KeyResult {None, Left, Right};
Implement this for different platforms (Android/iOS/UWP) accordingly and bind it to PCL project. (Check dependency service implementation for help)
Link it to platform-specific KeyUp event.
for android it would be like this:
Droid.KeyEventHandler
[assembly: Dependency(typeof(KeyEventHandler))]
namespace YourNameSpace.Droid
{
public class KeyEventHandler : IKeyEvent
{
public static KeyEventHandler Current;
public KeyEventHandler()
{
Current = this;
}
public event Action<KeyResult> OnKeyResult;
public void RaiseKeyEvent(KeyResult key)
{
OnKeyResult?.Invoke(key);
}
}
}
MainActivity
public override bool OnKeyUp(Keycode keyCode, KeyEvent e)
{
KeyResult keyResult = KeyResult.None; // need to reference YourNameSpace.Shared project to use this enum
if (keyCode == KeyCode.A)
{
keyResult = KeyResult.Left;
}
else if (keyCode == KeyCode.D))
{
keyResult = KeyResult.Right;
}
else
{
keyResult = KeyResult.None;
}
if (KeyEventHandler.Current != null)
{
KeyEventHandler.Current.RaiseKeyEvent(keyResult);
}
return base.OnKeyUp(keyCode, e);
}
NOTE: Left and right keys are mapped to A and D of physical keyboard respectively, for some reason my Macbook's F1/F2 keys were not registering to simulator so I used A/D.
Hope this helps :)

Resources