2016年10月27日木曜日

Unityで作ったアプリがメモリリーク!




どーもお久しぶりです。新事業部のありかわです。

最近Unityでゲームアプリを作っているのですが
久々にメモリリークではまってしまいました。

Unityに限らずオブジェクト指向言語ならGCが組み込まれていても、
オブジェクトへの参照が残りっぱなしになる状態が続くと
参照されてるオブジェクトは破棄されず、メモリリークになります。
当たり前ですけど。

そういった観点で色々調べて、Webでも

【Unity】DestroyしたオブジェクトのMaterialがリークする問題への対応
とか

DestroyしてUnloadUnusedAssetsしてもアセットがアンロードされない場合がある話
とか

参考にさせて頂いたのですが一向に原因がわからずめちゃくちゃ困ってました。

Unityファ○ク!!とか思ってたら、、AdMobのプラグインの使い方ミスってたのが原因でした。
Unityさんごめんなさい。

UnityでAdMobの広告を表示するのにBannerView、InterstitialAdといったクラスを使うんですが
使い終わったら各クラスのDestroy()メソッドを呼び出さないとリークの原因になるみたいです。

↓公式のサイトに書いてました。
ゲーム デベロッパー向け: 広告に関するおすすめの方法

ちゃんと読めや!って話ですよね。

それじゃまた。


2016年10月21日金曜日

ASP.NET Identityを利用して独自ユーザーを作る(後編)

今回はログインとパスワード変更です。

ログイン


前回登録したユーザーでログインしようとすると、またエラーが発生します。

Store does not implement IUserLockoutStore<TUser>.


var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
switch (result) {

どうしたものかとググってみると、このメソッドをオーバーライドしているサイトを見つけました。
同じようにオーバーライドします。

あとは、ストアクラスにパスワード取得メソッドを実装すればOKです。
public class ApplicationUserStore : IUserStore<ApplicationUser>, IUserPasswordStore<ApplicationUser>
{
    public Task<string> GetPasswordHashAsync(ApplicationUser user)
    {
        return Task.FromResult(user.PasswordHash);
    }
}

パスワード変更


パスワードの変更画面でパスワードを変更しようとすると、またまたエラーが発生します。

ストアは IUserEmailStore<TUser> を実装していません。


var result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword);
if (result.Succeeded) {

もうお分かりですよね?
ChangePasswordAsyncをオーバーライドします。
public override async Task<IdentityResult> ChangePasswordAsync(string userId, string currentPassword, string newPassword)
{
    var store = (ApplicationUserStore)this.Store;
    var user = await store.FindByIdAsync(userId);
    var result = await VerifyPasswordAsync(store, user, currentPassword);
    if (!result)
    {
        return IdentityResult.Failed("パスワードが正しくありません。");
    }
 
    var identifyResult = await UpdatePassword(store, user, newPassword);
    if (!identifyResult.Succeeded)
    {
        return identifyResult;
    }
 
    await store.UpdateAsync(user);
    return IdentityResult.Success;
}

必要なメソッドをストアクラスに実装します。
public class ApplicationUserStore : IUserStore<ApplicationUser>, IUserPasswordStore<ApplicationUser>
{
    public Task<ApplicationUser> FindByIdAsync(string userId)
    {
        return this._context.ApplicationUsers.SingleOrDefaultAsync(x => x.Id == userId);
    }
 
    public Task UpdateAsync(ApplicationUser user)
    {
        return this._context.SaveChangesAsync();
    }
}

これでパスワード変更ができました。

またいつか、どこかで。

2016年10月14日金曜日

ASP.NET Identityを利用して独自ユーザーを作る(前編)

ASP.NET Identityを初めて使っています。

非常に便利なのですが、VisualStudioでMVCテンプレートを選択して作成したプロジェクトでは、IdentityUserを継承しているためにメールアドレスや電話番号等が含まれており、シンプルに名前とパスワードだけを使いたいような場合にはオーバースペックですよね。
そこで、生成したプロジェクトをベースに、必要最小限のユーザー情報で登録・ログインなどができるように変更してみたいと思います。

ApplicationUserをIUserを実装するように変更し、パスワードを追加します。
public class ApplicationUser : IUser
{
    public string Id { getset; }
 
    public string UserName { getset; }
 
    public string PasswordHash { getset; }
 
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        var userIdentity = await manager.CreateIdentityAsync(thisDefaultAuthenticationTypes.ApplicationCookie);
        return userIdentity;
    }
}

コンテキストをDbContext派生にします。
public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }
 
    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
 
    public DbSet<ApplicationUser> ApplicationUsers { getset; }
}

IUserStoreを実装するストアクラスを新しく作ります。
public class ApplicationUserStore : IUserStore<ApplicationUser>
{
    private ApplicationDbContext _context;
 
    public ApplicationUserStore(ApplicationDbContext context)
    {
        this._context = context;
    }
 
    // IUserStoreインターフェースの実装は省略
}

作成したストアをユーザーマネージャーのコンストラクタに渡します。
public class ApplicationUserManager : UserManager<ApplicationUser>
{
    public ApplicationUserManager(IUserStore<ApplicationUser> store)
        : base(store)
    {
    }
 
    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) 
    {
        var manager = new ApplicationUserManager(new ApplicationUserStore(context.Get<ApplicationDbContext>()));
 
        // 省略

        return manager;
    }
}

これでビルドが通るようになりました。
デバッグを開始し、登録しようとするとエラーが発生します。

ストアは IUserPasswordStore<TUser> を実装していません。


{
    var user = new ApplicationUser { UserName = model.Email, };
    var result = await UserManager.CreateAsync(user, model.Password);
    if (result.Succeeded)
    {

ということで、ストアクラスにIUserPasswordStoreも実装します。
public class ApplicationUserStore : IUserStore<ApplicationUser>, IUserPasswordStore<ApplicationUser>
{
    private ApplicationDbContext _context;
 
    public ApplicationUserStore(ApplicationDbContext context)
    {
        this._context = context;
    }
 
    public void Dispose()
    {
    }
 
    public Task<ApplicationUser> FindByNameAsync(string userName)
    {
        return this._context.ApplicationUsers.SingleOrDefaultAsync(x => x.UserName == userName);
    }
 
    public Task SetPasswordHashAsync(ApplicationUser user, string passwordHash)
    {
        return Task.Run(() => user.PasswordHash = passwordHash);
    }
 
    // その他のインターフェースの実装は省略
}

再度、登録しようとするとまたエラーが発生しました。

ストアは IUserEmailStore<TUser> を実装していません。


{
    var user = new ApplicationUser { UserName = model.Email, };
    var result = await UserManager.CreateAsync(user, model.Password);
    if (result.Succeeded)
    {

IUserPasswordStoreはまだしも、さすがにIUserEmailStoreを実装するわけにはいきません。
CreateAsyncメソッドをオーバーライドすることにしました。
public class ApplicationUserManager : UserManager<ApplicationUser>
{
    public override async Task<IdentityResult> CreateAsync(ApplicationUser user, string password)
    {
        var store = (ApplicationUserStore)this.Store;
        var identityResult = await UpdatePassword(store, user, password);
        if (!identityResult.Succeeded)
        {
            return identityResult;
        }
 
        await store.CreateAsync(user);
        return IdentityResult.Success;
    }
}

ストアクラスの作成処理はこんな感じです。
public class ApplicationUserStore : IUserStore<ApplicationUser>, IUserPasswordStore<ApplicationUser>
{
    public Task CreateAsync(ApplicationUser user)
    {
        user.Id = Guid.NewGuid().ToString();
        this._context.ApplicationUsers.Add(user);
        return this._context.SaveChangesAsync();
    }
}

これで登録ができるようになりました。
次回はログインです。

またいつか、どこかで。

2016年10月7日金曜日

AdMobのアカウント



新事業部のありかわです。

先日、アプリで広告収入を得るためにAdMobのアカウントを作ろうとしたら

「 申し訳ございませんが、現時点では、お客様は AdMob をご利用いただけません。」
とか言われて作ることができませんでした。

いろいろ調べてたら、AdMobのアカウントを作るために使用したGoogleアカウントの生年月日が
1999年になっていました。(会社用のアカウントなので弊社創業日になってました。)
今年は2016年だから17歳なんですよねー。
AdMobのアカウントは18歳からしか作れないのです。

会社用のGoogleアカウントでAdMobのアカウントを開設する方は気をつけて!


それじゃまた。