fc2ブログ

記事一覧

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.");
}
        var task = new Task<string[]>(() =>
{
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;
});
task.Start();
task.Wait();
return task.Result;
    }
/// <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.");
}
        var task = new Task<string[]>(() =>
{
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;
});
task.Start();
task.Wait();
return task.Result;
    }
}

※HostInfo はPCLに配置している自作モデルクラスです。URL/IP/Protocol/UserName/Password などのプロパティを保持しています。
※smbの処理は全てTaskを使用して非同期にしましょう。非同期にしない場合、Android7にてAndroid.OS.NetworkOnMainThreadExceptionが発生します。



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からご覧になれます。
https://itblog.dynaspo.com/blog-entry-81.html


関連記事

コメント

コメントの投稿

※名前とタイトルが入力されていないコメントでは他のコメントとの区別ができません。

 入力されていないコメントには返信しませんのであらかじめご了承くださいませ。

※ニックネームでも良いので必ずご入力ください。

    

※必ずご入力ください。

    
    

※必ずご入力ください。

※技術的な質問には環境やエラーについて正確かつ詳細にお教えください。

・正確なエラーの内容

・Windowsのバージョン番号

・Visual Studioのバージョン

・機器の型番

・アプリやソフトのバージョン

    

カテゴリ別記事一覧

広告

プロフィール

石河 純


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

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Catalina 10.15 / Mojave 10.14 / High Sierra 10.13 / Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
【データベース】
Oracle 10g/9i
SQLServer 2016/2008R2/2005/2000
SQLAnywhere 16/11/8
【BI/レポートツール】
Cognos ReportNet (IBM)
Microsoft PowerBI
ActiveReport (GrapeCity)
CrystalReport
【OCX関連】
GrapeCity InputMan SPREAD MultiRow GridView
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS jQuery IIS6/7 apache2

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