記事一覧

AndroidにてLan内の共有フォルダに接続する方法 | Xamarin.Forms


Windows.Forms ではLan内の共有フォルダに接続する場合、Windows の機能(WinAPI32)を利用していましたので簡単に接続ができました。
Android では WinAPI32 の機能は一切利用できず、Xamarin にも今のところその機能は無い為、独自でコーディングする必要がありますが、それは大変なことであることが容易に想像できます。
そこで、Java で利用されている JCIFS というライブラリが存在していることを発見し、さらにはその JCIFS が C# で動作するように編成されているソースも公開されていました。
以下、C#で動作するJCIFSのソース
https://github.com/sushihangover/Xamarin.Android.jCIFS

JCIFSライブラリを利用して開発を行っていると、以下のエラーが表示され、原因の究明に時間がかかりましたので、ここにライブラリを利用する為の正しいソースを公開します。

Java.Lang.NoClassDefFoundError: jcifs/UniAddress


これはUniAddressというクラスが見つからないとのメッセージを示していますが、当然ビルドされたDLLも配置されていますので、最初意味が分かりませんでした。結局、このメッセージとは異なる内容で、ログイン処理を非同期にしていなかったことが原因でした。


前提条件
・Windows10
・Visual Studio 2015 Community Update3
・Xamarin 4.2.0.719 (NuGet Xamarin.Forms 2.3.2.127)


1.JCIFSを利用したC#ソース

Xamarin.Droidプロジェクトに記述します。(DependencyServiceにて呼び出します。)

using Jcifs;
using Jcifs.Smb;
using Xamarin.Forms;
using System.Threading.Tasks;
using System.Collections.Generic;
[assembly: Dependency(typeof(SmbService))]
public class SmbService : ISmbService
{
    private UniAddress _domain = null;
    private NtlmPasswordAuthentication _auth = null;
    private HostInfo _hostInfo = null;
    private SmbFile _smbFile = null;
private bool _isLogon = false;
/// <summary>
/// SmbFileインスタンスを保持する
/// </summary>
/// <param name="path">フルパス</param>
    private void CreateSmbInstance(string path)
    {
        if (_smbFile != null && _smbFile.Path.Equals(path))
        {
            //pathが変更ない場合はインスタンスを使いまわす。
            return;
        }
        else if (_smbFile != null)
        {
            _smbFile.Dispose();
        }
        _smbFile = new SmbFile(path, this._auth);
    }
/// <summary>
/// ホスト情報の受け渡し
/// </summary>
/// <param name="hostInfo">ホスト情報</param>
    public void SetHostInfo(HostInfo hostInfo)
    {
        if (hostInfo == null)
        {
            throw new Exception("Hostinfo is not set.");
        }
        _hostInfo = hostInfo;
    }
/// <summary>
/// ログオン処理
/// </summary>
    public void Logon(ref string err)
    {
        if (_hostInfo == null)
        {
            throw new Exception("Hostinfo is not set.");
        }
//ログイン処理を非同期で行う
var task = new Task<string>(() =>
{
try
{
this._domain = UniAddress.GetByName(_hostInfo.IP);
this._auth = new NtlmPasswordAuthentication(_hostInfo.IP, _hostInfo.UserName, _hostInfo.Password);
SmbSession.Logon(this._domain, this._auth);
_isLogon = true;
return String.Empty;
}
catch (Exception ex)
{
_isLogon = false;
return ex.Message;
}
});
task.Start();
task.Wait();
err = task.Result;
    }
/// <summary>
/// ディレクトリ一覧を取得する
/// </summary>
/// <param name="path">検索するフルパス</param>
/// <returns>ディレクトリ一覧</returns>
    public string[] GetDirectories(string path)
    {
        if (!_isLogon)
{
throw new Exception("You are not logged on to the remote host.");
}
        this.CreateSmbInstance(path);
        List<string> list = new List<string>();
        if (_smbFile.IsDirectory)
        {
            foreach (SmbFile dir in _smbFile.ListFiles())
            {
                if (dir.IsDirectory)
                {
                    list.Add(_smbFile.Path + dir.Name.Replace("/", ""));
                }
            }
            return list.ToArray();
        }
        return null;
    }
/// <summary>
/// ファイル一覧を取得する
/// </summary>
/// <param name="path">検索するフルパス</param>
/// <returns>ファイル一覧</returns>
    public string[] GetFiles(string path)
    {
        if (!_isLogon)
{
throw new Exception("You are not logged on to the remote host.");
}
        this.CreateSmbInstance(path);
        List<string> list = new List<string>();
        if (_smbFile.IsDirectory)
        {
            foreach (SmbFile dir in _smbFile.ListFiles())
            {
                if (dir.IsFile)
                {
                    list.Add(_smbFile.Path + dir.Name);
                }
            }
            return list.ToArray();
        }
        return null;
    }
}

※HostInfo はPCLに配置している自作モデルクラスです。URL/IP/Protocol/UserName/Password などのプロパティを保持しています。


2.注意点のまとめ

(1)フォルダの場合は 最後スラッシュで終わること。
例: smb://192.168.0.1/shared/
(2)非同期でログイン処理を行うこと。(Task Runの利用)
UniAddressを利用する場合は、Task Run 内に記載しなければならないようですね。



共有フォルダを利用したファイルのダウンロードとアップロード方法につきましては次回のブログにてご紹介しております。
匿名アクセスの方法についてはこちらをご覧ください。


2017/05/06追記
さらにiOSでも動作可能なNuGetパッケージが公開されました。上記のSharpCIFSを.Net版に移植したもののようです。
以下、iOSとAndroidで共通で使用できます。記述するソースもほとんど改変必要ありませんでした。
http://try-dot-net-core.hatenablog.com/entry/2016/12/28/140429




当ブログの内容をまとめた Xamarin逆引きメニュー は以下のURLからご覧になれます。
http://itblogdsi.blog.fc2.com/blog-entry-81.html


関連記事

コメント

コメントの投稿
非公開コメント

アルバム

広告

プロフィール

石河 純


著者名 :石河 純
自己紹介:素人上がりのIT技術者。趣味は卓球・車・ボウリング

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語・データベース】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
Oracle10g SQLServer2008R2 SQLAnywhere8/11/16
ActiveReport CrystalReport ReportNet(IBM)
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS IIS6/7 apache2

休みの日は卓球をやっています。
現在、卓球用品通販ショップは休業中です。